Django 表单 - 视图中的嵌套过滤以进行表单清理数据验证

Django forms - nested filtering in a vew for form cleaned data validation

这与 有关,但解决的问题略有不同。

我需要对表单数据进行两级检查:我有一个包含名称、姓氏和角色的个人资料模型(最后一个是来自相关模型的数组,一个个人资料可以有多个角色)。

提交表格后,我需要先检查是否存在具有名字和姓氏的个人资料;如果是,我需要检查现有配置文件是否已经具有该角色;如果是,则抛出错误。如果不是,保留现有配置文件,仅将新角色添加到现有配置文件

我的模特:

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

你的代码干净整洁,我喜欢它;)

我认为这个片段可以解决您的用例:

def clean(self):
    cleaned_data = super().clean()
    name = self.cleaned_data['name']
    surname = self.cleaned_data['surname']
    role = self.cleaned_data['role']

    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:
        pass

    return cleaned_data