django-postgres-extra adds upserts, partitioning and views to Django
Bringing all of PostgreSQL's awesomeness to Django.
At a glance
- What is it?
- django-postgres-extra is a Django library that exposes PostgreSQL features the ORM leaves out, notably atomic ON CONFLICT upserts, declarative table partitioning, views and materialized views, all integrated into migrations. It suits teams on PostgreSQL who have hit the boundary of the ORM, and it drops support for older Django versions as the major version moves.
- Who is it for?
- Adopt django-postgres-extra when you run Django on PostgreSQL and need ON CONFLICT upserts, partition tables, or database views without dropping to raw SQL, and when you want those features to appear in migrations rather than in hand written SQL. Do not adopt it if you need to stay on Django older than 5.0, since the major version raised the floor, and do not use it as a reason to skip the ORM entirely.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One package instead of a pile of single feature add-ons
django-postgres-extra exists to make PostgreSQL features available through the Django ORM, and the README is explicit about the positioning. The claim is that as opposed to the many small packages available to try to bring a single feature to Django with minimal effort, this package goes the extra mile with well tested implementations and seamless migrations. The word doing the work there is seamless, and the README defines it: you should not have to manually modify your migrations to work with the fields and objects the package provides. That is a sharper problem than it sounds. The usual pattern for an ORM extension is a custom field or manager that works at runtime but leaves the migration system unable to represent what the database actually contains, so the next makemigrations produces a no-op that does not match the real schema. A package that folds its features into migrations removes that gap. The project is published under the MIT licence, with the licence field in the packaging metadata reading MIT License, and it is maintained by Sector Labs.
Atomic upserts are the headline feature
Conflict handling is listed first among the major features, and it is the one most Django applications end up needing. The package adds support for PostgreSQL's ON CONFLICT syntax for inserts, supporting DO UPDATE and DO NOTHING, and the README describes the result as a single statement, atomic and concurrency safe upsert, with support for conditional updates as well. The distinction from doing this in Python is the whole point. A read-then-write in application code has a window between the two statements where a concurrent request can win, and the usual fixes are to catch the integrity error and retry or to take a lock, both of which are more code and more failure modes. ON CONFLICT moves the decision into the database, where the row is locked and the outcome is decided in one round trip. Conditional updates matter for a specific and common shape, where you only want to overwrite a column when a condition holds, which is hard to express safely outside the database. The features list links to the full documentation, and the topics on the repository name hstore and ltree alongside postgresql and django.
Partitioning and views are modelled, not bolted on
The second group is about making database objects first class in Django. Table partitioning adds support for PostgreSQL 11.x declarative table partitioning, integrated into Django migrations, supporting all types of partitioning, and it includes a command to automatically create time-based partitions. Time partitioning is the common case, since a table that accumulates rows forever eventually needs to be split, and doing that by hand inside a migration system is painful. Views and materialized views add support for creating them as any other model, also integrated into migrations, which means a view can be created, altered and dropped through the same mechanism that handles tables. The remaining features are smaller and more administrative. Locking models and tables gives support for explicit table-level locks, creating and dropping schemas covers managing PostgreSQL schemas, and truncating tables supports TRUNCATE TABLE statements including cascading, which is the fast way to empty a table when the foreign key graph allows it. There are also version conditional features, since conditional unique index and case insensitive index are listed for Django 3.1 and older, and unique index along with HStore unique and required constraints on specific HStore keys for Django 2.2 and older, reflecting features that newer Django versions handle natively.
Version support narrowed sharply in the 3.0 release
The release history shows the v3.0.0 release on 2026-10-02, preceded by a v3.0.0rc1 candidate the same day, with v2.0.9 from 2025-07-11 before that. The README also carries a warning that it is written for v2, with the v1 branch holding the older line. The compatibility table in the README lists Django versions from 2.0 through 5.2, Python versions from 3.7 to 3.13, and psycopg versions 2 and 3. The working-with-the-code section tells a different and more current story, and that is the one to plan against. Local development needs PostgreSQL 14 or newer, Django 5.x or newer, and Python 3.11 or newer, and the README clarifies that these are for local development and for the CI that runs code analysis, while tests pass on all the documented Python, Django and PostgreSQL versions. Linting, formatting and type checking may not work on the older ones. In other words, the wide compatibility table describes what the library runs against, while the current toolchain floor is much higher. A project pinning itself to an old Django version should treat the v2 line as the target, not the v3 one.
Setting up a development environment with uv
The getting started section is a seven step list and it uses uv rather than pip for the environment. You clone the repository, install uv if you do not have it, then sync the development and test dependencies, which creates a .venv and installs from uv.lock. The dependency freeze has a specific purpose worth naming. The README notes that uv.lock enforces a three day dependency cooldown through the exclude-newer setting in pyproject.toml, so newly published versions cannot enter your environment until the community has had time to flag a malicious release. That is a supply chain measure applied to the project's own development environment, and it is the kind of detail that says something about how the maintainers think about dependency risk. The remaining steps create a postgres superuser for the tests, set a DATABASE_URL pointing at that user, and then run the tests with poe test, the benchmarks with poe benchmark, and poe fix to auto-format code, sort imports and auto-fix linting errors.
The commands the documentation gives are these:
git clone https://github.com/SectorLabs/django-postgres-extra.git
curl -LsSf https://astral.sh/uv/install.sh | sh
uv sync --extra dev --extra test
poe testThe clone and the uv installer come first, then the sync creates the virtual environment from the lock file, and poe test runs the suite against the PostgreSQL instance you configured with DATABASE_URL.
Why the alternative of hand written SQL loses here
The realistic alternative is to skip the package and write the SQL yourself, either as raw SQL in a migration or in a custom manager. The difference in approach is where the complexity lives and who maintains it. A raw SQL migration works, and for a single table it is honestly the lighter option. The problems arrive as the schema grows, because a raw SQL migration is opaque to Django's migration state, so the next makemigrations cannot tell what the model and the database disagree about, and you end up maintaining a second source of truth. A custom manager leaves the schema in the database and the logic in Python, so an atomic upsert becomes a hand written statement and its behaviour has to be re-implemented and tested by you. The package's position is that the cost of these features is paid once, in a tested implementation, and then the ORM, the migrations and the model layer agree. What you give up is control over the exact SQL, and with a package that tracks a specific PostgreSQL feature set, some of the flexibility of writing the statement by hand is genuinely lost.
Where the library stops and what to check before adopting
The boundaries are clear once you know the project is PostgreSQL only. The features are PostgreSQL features, so there is no SQLite or MySQL path, and a test suite that runs against SQLite will not exercise any of them. There is also a floor on the server version, with PostgreSQL 14 or newer needed for development, and the partition and view features depend on the declarative partitioning and materialized view support that arrived in specific PostgreSQL releases. Beyond that, the package is a set of ORM extensions rather than a general database abstraction, so it does not give you a portable model layer, and it does not remove the need to understand the underlying SQL, because a conditional upsert that behaves differently from what you expected is still a database semantics question. The migration integration, which is the package's main argument, also has a practical cost. It means your migration history becomes coupled to the package being installed, so removing the package later is a real migration rather than a deletion. Check your PostgreSQL version, check the Django version you are on against the v2 and v3 split, and read the upgrade notes before you plan a version bump of your own.
Editorial conclusion
Adopt django-postgres-extra when you run Django on PostgreSQL and need ON CONFLICT upserts, partition tables, or database views without dropping to raw SQL, and when you want those features to appear in migrations rather than in hand written SQL. Do not adopt it if you need to stay on Django older than 5.0, since the major version raised the floor, and do not use it as a reason to skip the ORM entirely. Verify first that your PostgreSQL version is 14 or newer, that the upsert semantics you need match the supported DO UPDATE and DO NOTHING forms with conditional updates, and that your migration state can be regenerated with the package installed rather than edited by hand.
Frequently asked questions
What does django-postgres-extra add to the Django ORM?
It adds PostgreSQL ON CONFLICT upserts with DO UPDATE and DO NOTHING and conditional updates, declarative table partitioning with a command to create time-based partitions, views and materialized views as models, table-level locking, schema creation and dropping, and truncating tables including cascading. Several of these are integrated into Django migrations.
What are the version requirements for django-postgres-extra?
The documentation lists Django versions from 2.0 to 5.2, Python from 3.7 to 3.13 and psycopg 2 or 3, but the current development prerequisites are PostgreSQL 14 or newer, Django 5.x or newer and Python 3.11 or newer. The v3.0.0 release was published on 2026-10-02.
How do I set up a development environment for django-postgres-extra?
Clone the repository, install uv, then run uv sync --extra dev --extra test to create the virtual environment from uv.lock, create a postgres superuser for the tests, export a DATABASE_URL pointing at it, and run poe test, poe benchmark and poe fix. The lock file applies a three day dependency cooldown through exclude-newer in pyproject.toml.
Is django-postgres-extra licensed for commercial use?
The project is published under the MIT licence, with the licence field in the packaging metadata reading MIT License and a LICENSE file at the repository root. The README describes the goal as making PostgreSQL features available through the Django ORM with seamless migrations rather than requiring manual migration edits.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sectorlabs-django-postgres-extra)Was this useful?