DB constraints vs. clean() method in Django

After creating a clean() method to avoid overlapping date ranges in an admin form, I added an ExclusionContraint to ensure integrity at the DB level, too:

class DateRangeFunc(models.Func):
    function = 'daterange'
    output_field = DateRangeField()

class Occupancy(models.Model):
    unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
    number_of = models.IntegerField()
    begin = models.DateField()
    end = models.DateField(default=datetime.date(9999,12,31))

    class Meta:
        constraints = [
            ExclusionConstraint(
                name="exclude_overlapping_occupancies",
                expressions=(
                    (
                        DateRangeFunc(
                            "begin", "end", RangeBoundary(inclusive_lower=True, inclusive_upper=True)
                        ),
                        RangeOperators.OVERLAPS,
                    ),
                    ("unit", RangeOperators.EQUAL),
                ),
            ),
        ]

This constraint works as expected, but it seems to precede clean(), because any overlap raises an IntegrityError for the admin form. I would have expected that clean() is called first.

I have two questions (related, but not identical to this question):

  1. Is there any way to change the order of evaluation (clean()ExclusionConstraint)?
  2. Which method (save()?) would I need to override to catch the IntegrityError raised by the constraint?

[Django 4.1.5/Python 3.11.1/PostgreSQL 14.6]

Back to Top