Django constraint that IS NULL conditions of two columns must match

620 Views Asked by At

Consider the following model.

class MyModel(models.Model):
    a = models.DateField(blank=True, default=None, null=True)
    b = models.DateField(blank=True, default=None, null=True)

I'd like to require that both a and b are NULL, or both are NOT NULL. I can express this in raw DDL:

ALTER TABLE "app_mymodel" ADD CONSTRAINT "both_or_none_null" CHECK ((a IS NULL) = (b IS NULL));

To get this through Django, I tried

class Meta:
    constraints = [
        models.CheckConstraint(
                check=Q(a__isnull=F('b__isnull')),
                name='both_or_none_null'
            )
        ]

Alas, this produces django.core.exceptions.FieldError: Joined field references are not permitted in this query when I try to apply the resulting migration. I have therefore resorted to the less succinct

check=(Q(a__isnull=True) & Q(b__isnull=True)) | (Q(a__isnull=False) & Q(b__isnull=False))

which generates a correspondingly clunky DDL constraint. But my Django-foo is limited, so is there a way to express the original constraint correctly?

1

There are 1 best solutions below

0
Jack On

This should do it:

models.CheckConstraint(
   name="both_or_none_null",
   check=Q(a__isnull=True, b__isnull=True) | Q(a__isnull=False, b__isnull=False),
),