Michael
Michael

Reputation: 4461

ModelForm and unique_together validation

Django 1.10

The documentaion says that ModelForm validates unique together if clean method is correctly overridden. https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#overriding-the-clean-method

I have done something wrong as unique_together validation doesn't work.

>>> from wiki.models import Wiki
>>> Wiki.objects.all()
<QuerySet [<Wiki: image/1/fdfff>, <Wiki: image/1/fdffff>]>

Where image is related_model and 1 is related_id.

Could you help me understand what is wrong with this overriding?

class WikiForm(ModelForm):
    class Meta:
        model = Wiki
        fields = ['related_model', 'related_id', 'article']
        unique_together = (("related_model", "related_id"),)

    def validate_related_model(self):
        ...

    def validate_related_id(self):
        ...

    def clean(self):
        self.validate_related_model()
        self.validate_related_id()

        #  To maintain unique_together validation,
        #  we must call the parent class’s clean() method.
        return super(WikiForm, self).clean()

Upvotes: 1

Views: 1425

Answers (1)

denvaar
denvaar

Reputation: 2214

unique_together is a database-level constraint. It's supposed to be specified in the Meta class of the model, not the model form. For the validation to work as you would like, move it to the Wiki model. In your form, you probably won't even need to have those extra validation methods.

This doesn't look like it'd be the case for you, but also note that in order for the unique validation to work correctly, your model form must include all of the fields that are specified in the unique_together constraint. So, if related_model or related_id were excluded from the form, you'd need to do some extra work in order to allow the correct validation to happen:

def validate_unique(self):
    # Must remove organization field from exclude in order
    # for the unique_together constraint to be enforced.
    exclude = self._get_validation_exclusions()
    exclude.remove('organization')

    try:
        self.instance.validate_unique(exclude=exclude)
    except ValidationError, e:
        self._update_errors(e.message_dict)

In the example above I am removing organization from the form's list of excluded fields because it's part of the unique_together constraint.

Upvotes: 2

Related Questions