Давайте сначала проанализируем, когда два интервала (f 1 , т 1 ) и (f 2 , т 2 ) перекрытие. Проще решить проблему, когда выясняется, когда два интервала не перекрываются. Это верно для двух случаев:
- дано t 1 2 , с тех пор первое событие заканчивается раньше второго; или
- дано t 2 1 , поскольку первое событие заканчивается до начала второго.
Таким образом, это означает, что два события перекрываются с учетом t 1 & ge; f 2 и t 2 & ge; е 1 .
Обладая этими знаниями, мы можем разработать фильтр как:
bookings = Booking.objects.filter(
end_date__gte=form_start_date,
start_date__lte=form_end_date
)
return Item.objects.exclude(
booking__in=bookings
)
Это приводит к следующему запросу:
SELECT item.*
FROM item
WHERE NOT (
item.id IN (
SELECT V1.item_id
FROM booking V1
WHERE (V1.id IN (
SELECT U0.id FROM booking U0
WHERE (U0.end_date >= 2019-01-01 AND U0.start_date <= 2019-02-02)
AND V1.item_id IS NOT NULL
)
)
)
(здесь 2019-01-01
и 2019-02-02
- гипотетические даты начала и окончания).
Я думаю, что, вероятно, лучше обработать две даты через Form
, однако, чтобы сделать правильные проверки и очистки.
Например, если заполнить пустую базу данных данными, указанными в вопросе, мы получим:
>>> i1 = Item.objects.create(name='Item #01')
>>> i2 = Item.objects.create(name='Item #02')
>>> b1 = Booking.objects.create(item=i1, start_date=)
KeyboardInterrupt
>>> from datetime import date
>>> b1 = Booking.objects.create(item=i1, start_date=date(2019,1,1), end_date=date(2019, 1, 3))
>>> b2 = Booking.objects.create(item=i1, start_date=date(2019,1,11), end_date=date(2019, 1, 18))
>>> bookings = Booking.objects.filter(
... end_date__gte=date(2019, 1, 6),
... start_date__lte=date(2019, 1, 8)
... )
>>> Item.objects.exclude(
... booking__in=bookings
... )
<QuerySet [<Item: Item object (2)>, <Item: Item object (3)>]>
>>> b3 = Booking.objects.create(item=i2, start_date=date(2019,1,2), end_date=date(2019, 1, 6))
>>> bookings = Booking.objects.filter(
... end_date__gte=date(2019, 1, 6),
... start_date__lte=date(2019, 1, 8)
... )
>>> Item.objects.exclude(
... booking__in=bookings
... )
<QuerySet [<Item: Item object (2)>]>
Итак, сначала я сконструировал два предмета и сделал два заказа на первый предмет. Если мы затем сделаем запрос, мы увидим, что оба элемента всплывают. Если затем мы добавим дополнительное бронирование для Item #02
, то, если мы снова выполним запрос, мы увидим, что отображается только первый элемент (я сначала создал элемент для целей тестирования, который затем был удален), поскольку для данного диапазона , второй элемент больше не доступен: он был забронирован по бронированию b3
.