【发布时间】:2020-05-16 10:46:05
【问题描述】:
这与 Filter queryset with multiple checks, including value_is_in array in a Django view 有关,但解决了一个稍微不同的问题。
我需要对表单数据进行两个级别的检查:我有一个包含姓名、姓氏和角色的配置文件模型(最后一个是来自相关模型的数组,一个配置文件可以有多个角色)。
提交表格后,我需要先检查是否存在带有姓名和姓氏的个人资料;如果是,我需要检查该现有配置文件是否已经具有该角色;如果是,则抛出错误。如果没有,保留现有配置文件,仅将新角色添加到现有配置文件。
我的模型:
class Role(models.Model):
type= models.CharField(max_length=30)
def __str__(self):
return self.type
class Profile(models.Model):
first_name = models.CharField(max_length=120, null=True, blank=True)
surname = models.CharField(max_length=120, null=True, blank=True)
role = models.ManyToManyField(Role, blank=True)
这是我在表单中尝试过的:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['name', 'surname', 'role']
def clean(self):
cleaned_data = super().clean()
name = self.cleaned_data['name']
surname = self.cleaned_data['surname']
role = self.cleaned_data['role']
if Profile.objects.exclude(pk=self.instance.pk).filter(
name=name,
surname=surname,
role__in=role # this would check for all three fields at the same time. That's not what I want. I also want a second layer of filtering (see description).
).exists():
if role__in=role: # warning - pseudocode! This is just to show what I want to do.
raise forms.ValidationError("This profile already exists")
else: # append submitted role to EXISTING profile
else:
return cleaned_data
return cleaned_data
并查看:
def profile_add_view(request):
form_profile = ProfileForm(request.POST or None)
if form_profile.is_valid():
form_profile.save()
else:
return HttpResponseBadRequest('This profile already exists.')
这当然给了我第二个if role__in=role: 的语法错误。如何检查当前正在检查的 Profile 对象(来自exists() 方法的重复对象)是否具有表单中指定的角色?我真的需要使用 for 循环吗?
此外,我如何随后仅将该角色信息附加到该现有角色,而不创建具有不同角色的新配置文件?
最终代码
这是最终的工作代码,如果具有该名称和姓氏的配置文件根本不存在,也会保存一个新的配置文件。
def clean(self):
cleaned_data = super().clean()
name = self.cleaned_data['name']
surname = self.cleaned_data['surname']
role = self.cleaned_data['role'][0]
try:
profile = Profile.objects.get(name=name, surname=surname)
if profile.role.filter(type=role).exists():
raise forms.ValidationError("This profile already exists")
else:
# Add submitted role to existing Profile
profile.role.add(role)
except Profile.DoesNotExist:
newprofile = Profile.objects.create(name=name, surname=surname)
newprofile.role.add(role)
pass
【问题讨论】:
-
尽管您的解决方案确实有效,但我建议进行一次小的重构以使 ProfileForm 具有更标准的行为。你不应该在 clean() 中保存任何东西,因为调用 is_valid() 会产生意想不到的副作用。相反,我会在 save() 中创建/修改配置文件,并仅使用 clean() 进行验证,即使这意味着检查两次配置文件是否已经存在
-
好的,谢谢,这点很好。
标签: django django-forms django-views django-validation