Skip to main content

django-postgres-multirange

PyPI Python versions License Tests

PostgreSQL multirange fields for Django, built on the same primitives as django.contrib.postgres range fields.

A multirange is an ordered set of non-overlapping ranges — the native way to store things like available hours, blocked-out dates, or VLAN id spans in a single column.

Django declined to add these types to contrib.postgres. This package fills that gap.

Requirements

  • Python 3.10+
  • Django 5.2+
  • psycopg 3
  • PostgreSQL 14+ (developed against PostgreSQL 17)

Install

pip install django-postgres-multirange
# or, with the binary psycopg build:
pip install "django-postgres-multirange[binary]"

Add django.contrib.postgres to INSTALLED_APPS. Adding django_postgres_multirange is optional; the fields work without it.

Fields

Each range field Django already ships has a matching multirange:

Field PostgreSQL type Element
IntegerMultiRangeField int4multirange int4 / IntegerRangeField
BigIntegerMultiRangeField int8multirange int8 / BigIntegerRangeField
DecimalMultiRangeField nummultirange numeric / DecimalRangeField
DateTimeMultiRangeField tstzmultirange timestamptz / DateTimeRangeField
DateMultiRangeField datemultirange date / DateRangeField

Python values are psycopg.types.multirange.Multirange objects — a mutable sequence of Range. Lists of ranges or (lower, upper) pairs are accepted on assignment, the same way RangeField accepts a pair.

from django.contrib.postgres.indexes import GistIndex
from django.db import models
from django_postgres_multirange import IntegerMultiRangeField, Multirange
from psycopg.types.range import Range


class Schedule(models.Model):
    hours = IntegerMultiRangeField()

    class Meta:
        indexes = [GistIndex(fields=["hours"])]


Schedule.objects.create(hours=[(9, 12), (13, 17)])
row = Schedule.objects.get()
# PostgreSQL normalizes on write.
assert row.hours == Multirange([Range(9, 12), Range(13, 17)])

Continuous fields (DecimalMultiRangeField, DateTimeMultiRangeField) accept Django's default_bounds ("[)" by default) for pair input.

Empty ({} / Multirange()) is distinct from NULL.

Lookups

The lookups match RangeField, plus two that only make sense on a multirange:

Lookup Operator / function
contains @> element, range, or multirange
contained_by <@
overlap &&
fully_lt <<
fully_gt >>
not_lt &>
not_gt &<
adjacent_to `-
startswith / endswith lower() / upper() of the whole multirange
isempty isempty()
lower_inc, lower_inf, upper_inc, upper_inf bound tests
range_merge smallest covering range
len number of ranges
Schedule.objects.filter(hours__contains=10)
Schedule.objects.filter(hours__overlap=(12, 14))
Schedule.objects.filter(hours__contains=[(9, 10), (14, 15)])
Schedule.objects.filter(hours__range_merge__contains=16)
Schedule.objects.filter(hours__len=2)

GiST indexes and ExclusionConstraint work the same way they do for range fields (&&, @>, <@, …).

Development

make up     # Postgres 17 on localhost:54317
make test

See CONTRIBUTING.md for the full workflow.

Roadmap

Not in this release:

  • tsmultirange (Django has no tsrange counterpart)
  • union / intersection / difference / unnest database functions
  • range_agg / range_intersect_agg
  • user-defined range types
  • a non-JSON admin widget

License

BSD-3-Clause

Questions or issues: omar.bohsali@gmail.com

Metadata

Release files for django-postgres-multirange 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-postgres-multirange 0.1.0
File Size Uploaded Provenance Actions
django_postgres_multirange-0.1.0.tar.gz 15.2 kB With provenance Details for django_postgres_multirange-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-postgres-multirange 0.1.0
File Interpreter ABI Platform Actions
django_postgres_multirange-0.1.0-py3-none-any.whl Python 3 none any Details for django_postgres_multirange-0.1.0-py3-none-any.whl

Total release size: 27.5 kB

Release files / django_postgres_multirange-0.1.0.tar.gz

Download URL django_postgres_multirange-0.1.0.tar.gz
Size 15.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1aeb864950b5beb5e39db979fea1676a650bc8693010a15d55b0dc390df0a717
BLAKE2b-256 checksum
How to use checksums
0c7afbdb12acbd8f97faf0722e637fb41705400a834b18e19119b9b36867cdf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Release files / django_postgres_multirange-0.1.0-py3-none-any.whl

Download URL django_postgres_multirange-0.1.0-py3-none-any.whl
Size 12.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8539104cd3e58c80abc6d17f2f6a181d855718403a219c09375f1e5ce3a698a2
BLAKE2b-256 checksum
How to use checksums
1fe3096c999089de1f306d2d0a64c403f1fbd9c97d33b52f0ee0b32b286207b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Security for django-postgres-multirange 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_postgres_multirange-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page