Range fields — the full lookups

Django ORM PostgreSQL May 22, 2026 python

Range fields (DateTimeRange, DateRange, IntegerRange, DecimalRange) store an interval in one column.

python
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# ======================================================================
# Range fields (`DateTimeRange`, `DateRange`, `IntegerRange`, `DecimalRange`)
# store an interval in one column. Lookups map to PostgreSQL range operators:
# `__overlap` (`&&`), `__adjacent_to` (`-|-`), `__fully_lt`/`__fully_gt`
# (`<<`/`>>`), `__contains` (`@>`), `__contained_by` (`<@`), plus bound
# transforms like `__startswith` (lower bound) and `__isempty`.
# ======================================================================

# ----------------------------------------------------------------------
# during overlaps [6/4, 6/7)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(during__overlap=Range(dt(2026,6,4), dt(2026,6,7)))

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE "examples_reservation"."during" && '["2026-06-04 00:00:00+00:00","2026-06-07 00:00:00+00:00")'::tstzrange

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)
#   room 202 [2026-06-02 00:00:00+00:00, 2026-06-06 00:00:00+00:00)

# ----------------------------------------------------------------------
# during adjacent to [6/9, 6/12)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(during__adjacent_to=Range(dt(2026,6,9), dt(2026,6,12)))

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE "examples_reservation"."during" -|- '["2026-06-09 00:00:00+00:00","2026-06-12 00:00:00+00:00")'::tstzrange

# Result:
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)

# ----------------------------------------------------------------------
# price_band fully below [300, 400)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(price_band__fully_lt=Range(300, 400))

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE "examples_reservation"."price_band" << '[300,400)'

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)
#   room 202 [2026-06-02 00:00:00+00:00, 2026-06-06 00:00:00+00:00)

# ----------------------------------------------------------------------
# price_band contains the value 175
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(price_band__contains=175)

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE "examples_reservation"."price_band" @> (175)::integer

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)

# ----------------------------------------------------------------------
# amount range overlaps [190, 210)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(amount__overlap=Range(Decimal("190"), Decimal("210")))

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE "examples_reservation"."amount" && '[190,210)'::numrange

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)

# ----------------------------------------------------------------------
# date_span lower bound is 2026-06-01 (__startswith)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(date_span__startswith=date(2026, 6, 1))

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE lower("examples_reservation"."date_span") = '2026-06-01'::date

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)

# ----------------------------------------------------------------------
# price_band is not empty (__isempty=False)
# ----------------------------------------------------------------------

# Django:
Reservation.objects.filter(price_band__isempty=False)

# SQL:
#   SELECT "examples_reservation"."id", "examples_reservation"."room", "examples_reservation"."during", "examples_reservation"."price_band", "examples_reservation"."date_span", "examples_reservation"."amount", "examples_reservation"."seq"
#   FROM "examples_reservation"
#   WHERE NOT isempty("examples_reservation"."price_band")

# Result:
#   room 101 [2026-06-01 00:00:00+00:00, 2026-06-05 00:00:00+00:00)
#   room 101 [2026-06-05 00:00:00+00:00, 2026-06-09 00:00:00+00:00)
#   room 202 [2026-06-02 00:00:00+00:00, 2026-06-06 00:00:00+00:00)