Django constraint on derived fields
I am trying to add a non-overlaping constraint on a Postgres specific field DateRange field:
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateRangeField, RangeOperators
class MyModel(models.Model):
timespan = DateRangeField(blank=False, null=False)
status = models.CharField(max_length=8, choices=status_choices, blank=False, null=False)
class Meta:
constraints = [
ExclusionConstraint(
name='exclude_overlapping_offer',
expressions=[
('timespan', RangeOperators.OVERLAPS),
(models.Q(status='ACCEPTED'), RangeOperators.EQUAL),
],
)
Basically I want to prevent having overlapping entries in the database that have status ACCEPTED.
The migration runs fine, but then when I try to save the model, I get an error:
AttributeError: 'Q' object has no attribute 'replace_expressions'
There is a reply on a bug report that says that Q objects are not allowed in the expressions of the constraint:
https://code.djangoproject.com/ticket/34805
Is there some other way to have the constraint on a derived field?
The answer lies here:
https://docs.djangoproject.com/en/5.1/ref/contrib/postgres/constraints/
condition
ExclusionConstraint.condition A Q object that specifies the condition to restrict a constraint to a subset of rows. For example, condition=Q(cancelled=False). These conditions have the same database restrictions as django.db.models.Index.condition
Use condition
to supply the non-range value you want to filter the rows you want to apply the range restrictions to.