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

查看:164
本文介绍了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)

这有效,但是,因为用户不是

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的验证,而不是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)?

推荐答案

在<$ c $中设置 form.instance.user c> form_valid 为时已晚,因为那时表单已经被验证。由于这是 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 实例进行传递:

You could override get_form_kwargs, and pass in a CourseStudent instance with the user already set:

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天全站免登陆