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()