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