Prevent DateRangeField overlap in Django model?
I know that the answer is old, but now you can just create a constrain in the meta of the model, that will make Postgres handle this
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
from django.db import models
from django.db.models import Q
class Room(models.Model):
number = models.IntegerField()
class Reservation(models.Model):
room = models.ForeignKey('Room', on_delete=models.CASCADE)
timespan = DateTimeRangeField()
cancelled = models.BooleanField(default=False)
class Meta:
constraints = [
ExclusionConstraint(
name='exclude_overlapping_reservations',
expressions=[
('timespan', RangeOperators.OVERLAPS),
('room', RangeOperators.EQUAL),
],
condition=Q(cancelled=False),
),
]
Postgress Coonstraints
You can check this in your model full_clean
method, which is called automatically during ModelForm validation. It is NOT called automatically if you directly save the object.. this is a known problem with Django validation that you may be aware of already! So if you want validation any time the object is saved, you have to also override the model save
method.
class Booking(models.model):
def full_clean(self, *args, **kwargs):
super(Booking, self).full_clean(*args, **kwargs)
o = Booking.objects.filter(date_range__overlap=self.date_range).exclude(pk=self.pk).first()
if o:
raise forms.ValidationError('Date Range overlaps with "%s"' % o)
# do not need to do this if you are only saving the object via a ModelForm, since the ModelForm calls FullClean.
def save(self):
self.full_clean()
super(Booking, self).save()