【问题标题】:Django forms - nested filtering in a vew for form cleaned data validationDjango 表单 - 用于表单清理数据验证的视图中的嵌套过滤
【发布时间】: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


【解决方案1】:

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

我认为这个 sn-p 可以解决您的用例:

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

【讨论】:

  • 您好,谢谢。 role__in 实际上对我来说很好。请再次阅读我的问题:您是第二个误解我的问题的用户(第一个现在删除了他们的答案),尽管我认为这很清楚。
  • 您好,有误会请见谅。我相应地更新了我的答案。请注意,在您的个人资料模型中,“first_name”应重命名为“name”。 br
  • 啊,这样更好。几乎就在那里:此代码再次保存了一个具有两个角色的附加(重复)用户,将现有用户保留在那里。或者实际上,使用新角色保存一个新用户,并将新角色添加到现有角色中。令人困惑。
  • 我想一种解决方案是获取现有配置文件的角色,删除该角色,然后保存包含所有角色(旧角色和新角色)的新配置文件。
  • 正在创建副本,因为您仍在视图中调用form_profile.save()。您只需致电form_profile.is_valid() 即可应用更改。
猜你喜欢
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 2023-04-05
  • 1970-01-01
  • 2015-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多