Range fields (DateTimeRange, DateRange, IntegerRange, DecimalRange) store an interval in one column.
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) |