Django:验证具有排除字段的 ModelForm 中的 unique_together 约束 [英] Django: validating unique_together constraints in a ModelForm with excluded fields

查看:49
本文介绍了Django:验证具有排除字段的 ModelForm 中的 unique_together 约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表格:

class CourseStudentForm(forms.ModelForm):

    class Meta:
        model = CourseStudent
        exclude = ['user']

对于有一些复杂要求的模型:

for a model with some complicated requirements:

class CourseStudent(models.Model):

    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    semester = models.ForeignKey(Semester)
    block = models.ForeignKey(Block)
    course = models.ForeignKey(Course)
    grade = models.PositiveIntegerField()

    class Meta:
        unique_together = (
            ('semester', 'block', 'user'), 
            ('user','course','grade'),
        )

我希望新对象使用 CourseStudent.user 的当前登录用户:

I want the new object to use the current logged in user for CourseStudent.user:

class CourseStudentCreate(CreateView):
    model = CourseStudent
    form_class = CourseStudentForm
    success_url = reverse_lazy('quests:quests')


    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(CourseStudentCreate, self).form_valid(form)

然而,这是有效的,因为用户不是表单的一部分,它错过了 Django 否则会对 unique_together 约束进行的验证.

This works, however, because the user is not part of the form, it misses the validation that Django would otherwise do with the unique_together constraints.

如何让我的表单和视图使用 Django 对这些约束的验证,而不必自己编写?

How can I get my form and view to use Django's validation on these constraints rather than having to write my own?

我虽然在表单的隐藏字段中传递用户(而不是排除它),但这似乎不安全(即可以更改用户值)?

I though of passing the user in a hidden field in the form (rather than exclude it), but that appears to be unsafe (i.e. the user value could be changed)?

推荐答案

form_valid 中设置 form.instance.user 来不及了,因为表单已经验证过了到时.由于这是您的 form_valid 方法所做的唯一自定义操作,您应该将其删除.

Setting form.instance.user in form_valid is too late, because the form has already been validated by then. Since that's the only custom thing your form_valid method does, you should remove it.

您可以覆盖 get_form_kwargs,并在用户已经设置的情况下传入一个 CourseStudent 实例:

class CourseStudentCreate(CreateView):
    model = CourseStudent
    form_class = CourseStudentForm
    success_url = reverse_lazy('quests:quests')

    def get_form_kwargs(self):
        kwargs = super(CreateView, self).get_form_kwargs()
        kwargs['instance'] = CourseStudent(user=self.request.user)
        return kwargs

这还不足以让它发挥作用,因为表单验证跳过了引用 user 字段的唯一组合约束.解决方案是覆盖模型表单的 full_clean() 方法,并显式调用 validate_unique() 在模型上.覆盖 clean 方法(正如您通常会做的那样)不起作用,因为此时尚未使用表单中的值填充实例.

That isn't enough to make it work, because the form validation skips the unique together constraints that refer to the user field. The solution is to override the model form's full_clean() method, and explicitly call validate_unique() on the model. Overriding the clean method (as you would normally do) doesn't work, because the instance hasn't been populated with values from the form at that point.

class CourseStudentForm(forms.ModelForm):

    class Meta:
        model = CourseStudent
        exclude = ['user']

    def full_clean(self):
        super(CourseStudentForm, self).full_clean()
        try:
            self.instance.validate_unique()
        except forms.ValidationError as e:
            self._update_errors(e)

这篇关于Django:验证具有排除字段的 ModelForm 中的 unique_together 约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆