reservations: Add generated Reservation.timespan field and use it for filtering

This commit is contained in:
Adam Goldsmith 2024-09-09 19:15:01 -04:00
parent d25f1e673a
commit d19b2d19fb
2 changed files with 34 additions and 7 deletions

View File

@ -0,0 +1,24 @@
# Generated by Django 5.1.1 on 2024-09-09 21:32
import django.contrib.postgres.fields.ranges
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("reservations", "0002_externalreservation"),
]
operations = [
migrations.AddField(
model_name="reservation",
name="timespan",
field=models.GeneratedField(
db_persist=True,
expression=models.Func(
models.F("start"), models.F("end"), function="tstzrange"
),
output_field=django.contrib.postgres.fields.ranges.DateTimeRangeField(),
),
),
]

View File

@ -3,11 +3,13 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import DateTimeRangeField
from django.db import models
from django.db.models import F, Q, QuerySet
from django.utils import timezone
from model_utils.managers import InheritanceQuerySetMixin
from psycopg.types.range import Range
if TYPE_CHECKING:
from collections.abc import Iterable
@ -55,31 +57,32 @@ class ReservationQuerySet(InheritanceQuerySetMixin, QuerySet):
Selects events that are after the specified datetime, including
overlaps but excluding exactly matching endpoints.
"""
return self.filter(Q(start__gt=start) | Q(end__gt=start))
return self.filter(timespan__overlap=Range(start, None))
def filter_before(self, end: datetime) -> ReservationQuerySet:
"""
Selects events that are before the specified datetime, including
overlaps but excluding exactly matching endpoints.
"""
return self.filter(Q(start__lt=end) | Q(end__lt=end))
return self.filter(timespan__overlap=Range(None, end))
def filter_between(self, start: datetime, end: datetime) -> ReservationQuerySet:
"""
Selects events that are between the specified datetime, including
overlaps but excluding exactly matching endpoints.
"""
return self.filter(
Q(start__gt=start, start__lt=end)
| Q(end__gt=start, end__lt=end)
| (Q(start__lt=start) & Q(end__gt=end))
)
return self.filter(timespan__overlap=Range(start, end))
class Reservation(models.Model):
resources = models.ManyToManyField(Resource, blank=True)
start = models.DateTimeField()
end = models.DateTimeField()
timespan = models.GeneratedField(
expression=models.Func(F("start"), F("end"), function="tstzrange"),
output_field=DateTimeRangeField(),
db_persist=True,
)
google_calendar_event_id = models.CharField(
max_length=1024, null=True, blank=True, unique=True
)