7👍
Two intervals (s1, t1) and (s2, t2) do not overal, given t1 < s2, or t2 < s1. This thus means that two resources overlap given t1 ≥ s2 and t2 ≥ s1.
This thus means that you should implement a check like:
def isAvaible(self, endDate, initialDate):
return not self.reunion_set.filter(end__gte=intialDate, start__lte=endDate).exists()
Note that you should not use .get(..)
[Django-doc] here, since this will raise an error when there are no records, or when there are multiple records (two or more). You here can make use of .exists()
[Django-doc] to find out if such record exists.
1👍
The answer of Willem will work for most of the cases. However, when we have an invalid interval i.e. start_date
is after end_date
, it won’t work.
I have made a generic function by referencing a similar question.
from django.db.models import Q
def create_query_for_finding_overlapping_intervals(start_date_column, end_date_column_name, start_dt, end_dt,
closed_interval=True):
"""
Creates a query for finding intervals in the Django model which overlap the [start_date, end_date] closed interval.
It also takes care of the invalid interval case when start date > end date for both stored ones and the input ones.
:param start_date_column: name of start date column in the model
:param end_date_column_name: name of end date column in the model
:param start_dt: start date of the interval to be checked
:param end_dt: end date of the interval to be checked
:param closed_interval: closed interval = True means intervals are of the form [start, end],
otherwise intervals are of the form [start, end). Where ")" means end-value is included and ")" end-value is not
included.
:return:
"""
q_start_dt__gt = f'{start_date_column}__gt'
q_start_dt__gte = f'{start_date_column}__gte'
q_start_dt__lt = f'{start_date_column}__lt'
q_start_dt__lte = f'{start_date_column}__lte'
q_end_dt__gt = f'{end_date_column_name}__gt'
q_end_dt__gte = f'{end_date_column_name}__gte'
q_end_dt__lt = f'{end_date_column_name}__lt'
q_end_dt__lte = f'{end_date_column_name}__lte'
q_is_contained = Q(**{q_start_dt__gte: start_dt}) & Q(**{q_end_dt__lte: end_dt})
q_contains = Q(**{q_start_dt__lte: start_dt}) & Q(**{q_end_dt__gte: end_dt})
q_slides_before = Q(**{q_start_dt__lt: start_dt}) & Q(**{q_end_dt__lt: end_dt})
q_slides_after = Q(**{q_start_dt__gt: start_dt}) & Q(**{q_end_dt__gt: end_dt})
if closed_interval:
q_slides_before = q_slides_before & Q(**{q_end_dt__gte: start_dt})
q_slides_after = q_slides_after & Q(**{q_start_dt__lte: end_dt})
else:
q_slides_before = q_slides_before & Q(**{q_end_dt__gt: start_dt})
q_slides_after = q_slides_after & Q(**{q_start_dt__lt: end_dt})
return q_contains | q_is_contained | q_slides_before | q_slides_after
Usage:
def isAvaible(self, endDate, initialDate):
query_obj = create_query_for_finding_overlapping_intervals('start', 'end', initialDate, endDate)
return not self.reunion_set.filter(query_obj).exists()
1👍
@damjad solution worked for me but with a little modification at the last line which should be like this:
return q_contains | q_is_contained | q_slides_before | q_slides_after