Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unique together constraint including specific field value

Tags:

python

django

For one of my models, I need to ensure the unicity of some rows, but only in a certain case. Only the "validated" rows should follow this constraint.

Basically, I'm looking forward something like

class MyModel(models.Model):
    field_a = models.CharField()
    field_b = models.CharField()
    validated = models.BooleanField(default=False)

    class Meta:
        unique_together = (('field_a', 'field_b', 'validated=True'),)
like image 200
Anto Avatar asked Feb 21 '14 16:02

Anto


2 Answers

You can use UniqueConstraint in case you're using Django 2.2+ Here is an example

class MyModel(models.Model):
    field_a = models.CharField()
    field_b = models.CharField()
    validated = models.BooleanField(default=False)

    class Meta:
        constraints = [
            UniqueConstraint(fields=['field_a', 'field_b'], condition=Q(validated=True), name='unique_field_a_field_b_validated')
        ]

here is the source

like image 104
Vaghinak Avatar answered Sep 27 '22 18:09

Vaghinak


(at time of writing, in Django < 2.2)

You can't do that with unique_together in Django, presumably because not all db backends would be able to support it.

You can do it in the application layer with model validation instead:
https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

eg

class MyModel(models.Model):
    field_a = models.CharField()
    field_b = models.CharField()
    validated = models.BooleanField(default=False)

    def clean(self):
        if not self.validated:
            return
        existing = self.__class__.objects.filter(field_a=self.field_a,
                                                 field_b=self.field_b).count()
        if existing > 0:
            raise ValidationError(
                "field_a and field_b must be unique if validated=True"
            )

Note that you will probably have to call the model validation manually, i.e.

instance.clean()
instance.save()

It is not done automatically when saving the model. On the other hand it is done automatically when using a ModelForm, i.e.

if form.is_valid():
    instance = form.save()
like image 29
Anentropic Avatar answered Sep 27 '22 17:09

Anentropic