#36627 new Uncategorized

Support PostgreSQL 18+ temporal constraints

Reported by: Adam Johnson Owned by:
Component: contrib.postgres Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

PostgreSQL 18 comes with support for "temporal constraints". These allow adding a special modifier to the final column in a unique constraint (WITHOUT OVERLAPS), primary key (WITHOUT OVERLAPS), or foreign key (PERIOD) which turns that column into a kind of "period specifier". This allows enforcing the given constraint is valid only for the range of that period. While the feature is not time-specific, the natural use case is to enforce uniqueness / validness over time, hence the name.

I propose that we add support for this feature in Django's UniqueConstraint, through some a new expression WithoutOverlaps in django.contrib.postgres, which would be used like this:

from django.db import models
from django.contrib.postgres.constraints import WithoutOverlaps
from django.contrib.postgres.fields import DateTimeRangeField

class Booking(models.Model):
    title = models.TextField()
    room = models.ForeignKey(Room, on_delete=models.CASCADE)
    span = DateTimeRangeField()
    
    class Meta:
        constraints = [
            models.UniqueConstraint(
                "room",
                WithoutOverlaps("span"),
                name="%(app_label)s_%(class)s_room_span_no_overlaps"
            ),
        ]

This could compile down to SQL like UNIQUE (room_id, span WITHOUT OVERLAPS).

It may also be possible, but more tricky, to support the other two ways to specify temporal constraints:

  • Primary key support would need to modify or subclass CompositePrimaryKey to support WithoutOverlaps for the final column.
  • Foreign key support would need to modify or subclass ForeignObject, which is still a private API.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top