1

This is my models to store availability of particular time when a new booking there

class TimeSlot(models.Model):
day = models.ForeignKey(
    Day,
    on_delete=models.CASCADE,
    related_name="time"
)
booking = models.ForeignKey(
    Booking,
    on_delete=models.CASCADE,
    related_name="time"
)
start_hour = models.TimeField()
end_hour = models.TimeField()

class Meta:
    unique_together = [('end_hour', 'start_hour',)]


def clean(self):
    pass

Currently it's allowing booking even those are considered as duplicate in terms of end_hour and start_hour. I want to prevent the slot, so that no new booking shouln't placed between a range that already booked.

Can anyone know how to do it with the range?

1 Answers1

0

I assume the problem is that start_hour and end_hour that fall within an already existing time range are allowed to be added. Of course the unique_together constraint cannot handle this as it only deals with uniqueness not uniqueness in a range. Instead you can override your models clean method and perform this validation there:

from django.db.models import Q
from django.core.exceptions import ValidationError


class TimeSlot(models.Model):
    day = models.ForeignKey(
        Day,
        on_delete=models.CASCADE,
        related_name="time"
    )
    booking = models.ForeignKey(
        Booking,
        on_delete=models.CASCADE,
        related_name="time"
    )
    start_hour = models.TimeField()
    end_hour = models.TimeField()
    
    class Meta:
        unique_together = [('end_hour', 'start_hour',)]
    
    
    def clean(self):
        start_hour_in_range = Q(start_hour__lte=self.start_hour, end_hour__gte=self.start_hour)
        end_hour_in_range = Q(start_hour__lte=self.end_hour, end_hour__gte=self.end_hour)
        # Queryset that finds all clashing timeslots with the same day
        queryset = self._meta.default_manager.filter(start_hour_in_range | end_hour_in_range, day=self.day)
        if self.pk:
            queryset = queryset.exclude(pk=self.pk) # Exclude this object if it is already saved to the database
        if queryset.exists():
            raise ValidationError('An existing timeslot clashes with the given one!')

Next if you are using a ModelForm this method would be called automatically or if you are not you can call instance.full_clean() which will call this method and all other cleaning methods on the model (clean_fields and validate_unique).

Abdul Aziz Barkat
  • 19,475
  • 3
  • 20
  • 33