Django 2.2 added a new constraints API which makes addressing this case much easier within the database.
You will need two constraints:
- The existing tuple constraint; and
- The remaining keys minus the nullable key, with a condition
If you have multiple nullable fields, I guess you will need to handle the permutations.
Here’s an example with a thruple of fields that must be all unique, where only one NULL
is permitted:
from django.db import models
from django.db.models import Q
from django.db.models.constraints import UniqueConstraint
class Badger(models.Model):
required = models.ForeignKey(Required, ...)
optional = models.ForeignKey(Optional, null=True, ...)
key = models.CharField(db_index=True, ...)
class Meta:
constraints = [
UniqueConstraint(fields=['required', 'optional', 'key'],
name="unique_with_optional"),
UniqueConstraint(fields=['required', 'key'],
condition=Q(optional=None),
name="unique_without_optional"),
]