kdt
kdt

Reputation: 28499

Django: more complex uniqueness constraint?

In my model:

class MyModel(models.Model):
  active = models.BooleanField()
  path = models.CharField(max_length = 512)

I would like to constrain that the 'path' attribute is unique amongst instances where active is True.

It seems like overriding save() might not work, as if two saves are done concurrently, both might pass the test and go ahead and save. Is there some trick or custom SQL (I'm using MySQL) I could use to have a conditional uniqness constraint like this at the database level?

Upvotes: 2

Views: 1339

Answers (2)

Kye
Kye

Reputation: 4495

Accidentally came across this whilst looking for something else, but for anyone else who ends up here, this is quite simple in Django >= 2.2 (which came out long after this question was asked) thanks to UniqueConstraint.

from django.db.models import Q, UniqueConstraint

class MyModel(models.Model):

    active = models.BooleanField()

    path = models.CharField(max_length=512)

    class Meta:
        constraints = [UniqueConstraint(fields=["path"], condition=Q(active=True)]

Upvotes: 1

Matthew Schinckel
Matthew Schinckel

Reputation: 35629

What you are probably looking for is Model Validation. This was introduced in 1.2, and is quite well documented. Django Models Instances : Validating Objects

Whilst you may be able to write some tricky SQL to do this, as long as the database rows are all created through the Django ORM, then model validation is the more maintainable solution.

Aside: I'm interested in how you'd do it at the database level, short of having some level of pre-commit trigger. Uniqueness of one value dependent upon another being true is something I haven't seen a pattern for. Having a 2-field unique constraint on active+path would allow 1 false, 1 true and any number of NULL active rows for a given path value (assuming active is nullable, such as a NullBooleanField would provide).

Upvotes: 2

Related Questions