Django: validating unique_together constraints in a ModelForm with excluded fields

我与影子孤独终老i 提交于 2019-12-07 16:15:13

问题


I have a form:

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'),
        )

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.

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)?


回答1:


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.

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

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)


来源:https://stackoverflow.com/questions/32260785/django-validating-unique-together-constraints-in-a-modelform-with-excluded-fiel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!