2

When UniqueConstraint of a model is violated, an exception is raised. How can I make it to behave the same as violation of a field with unique=True?

identifier = models.CharField("id", max_length=30, unique=True, blank=True, null=True, validators=[validate_id])

class Meta:
    constraints = [
        models.UniqueConstraint(
            Lower("identifier"),
            name="id_case_insensitive_constraint"
        )
    ]

Here I want a form's form_invalid called with the same field errors and all that, whether the input is exactly the same as another one or its only difference is case distinction.

aaronn
  • 448
  • 1
  • 6
  • 16
  • 2
    You will need to implement the logic in the `clean` method of the model, or in the `clean_fieldname` of the form. – Willem Van Onsem May 01 '22 at 08:45
  • @WillemVanOnsem Do you mean to catch the `IntegrityError` and then implement everything myself? From where should I get the field error message of the 'identifier' field? – aaronn May 01 '22 at 08:57
  • 1
    yes, the constraints are not translated into their Python validator equivalent. You can use `clean_identifier` in your form to validate a specific field: https://docs.djangoproject.com/en/4.0/ref/forms/validation/#cleaning-a-specific-field-attribute – Willem Van Onsem May 01 '22 at 08:59

1 Answers1

1

The constraints are not translated into validators: the validation is done entirely at the database side, so Django can not know in advance that the item will be invalid.

You can make a validator, for example in the ModelForm to validate this yourself, with:

from django import forms
from django.core.exceptions import ValidationError

class MyModelForm(forms.ModelForm):
    
    def clean_identifier(self):
        data = self.cleaned_data['identifier']
        if MyModel.objecs.exclude(pk=self.instance.pk).filter(identifier__iexact=data).exists():
            raise ValidationError('The identifier already exists')
        return data
    
    class Meta:
        model = MyModel
        fields = ['identifier']
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Is there a way to do this at the model level? because it's still possible to set this field to invalid values. – aaronn May 03 '22 at 09:51