django-model-utils: the mixins JazzBand maintains for Django models you write twice
Django model mixins and utilities.
At a glance
- What is it?
- TimeStampedModel, ChoiceField, InheritanceManager and friends. A small, typed, long-lived package that fills the gaps Django leaves in every project.
- Who is it for?
- django-model-utils earns its place by being the code you would otherwise copy between projects, kept typed and kept tested. The mixins are individually small and deliberately non-magical, which means you can read one and understand it in a minute.
- Can I use it commercially?
- Yes. BSD-3-Clause 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 16 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 September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A README that points at documentation instead of describing features
The README is reStructuredText, not Markdown, and it is short. After the badges it says what the package is in one line, Django model mixins and utilities, states that django-model-utils supports Django 3.2 and later, gives a PyPI link, and then points you at the issue tracker and the contributing guide. There is not a single feature list, no example, and no code sample.
That is a defensible choice for a package with a real documentation site at `django-model-utils.readthedocs.io`, which is where the mixin reference actually lives. It does mean the repository offers no way to judge the package without leaving it, which is why this article spends more time on `setup.py` than the README does.
The badges themselves are a small lesson in the JazzBand convention. The Jazzband badge sits at the top, followed by a GitHub Actions test badge, a codecov coverage badge pointing at the `master` branch, and PyPI badges for version, supported Python versions and supported Django versions. The last of those is generated by a service that reads the package classifiers, so the declared support range and the badge cannot drift apart.
The packaging says Django 4.2, the README says 3.2
This is the single most useful thing to find in the repository, and it is a real disagreement rather than a matter of interpretation.
The README states that django-model-utils supports Django 3.2 and later. `setup.py` says something narrower. It sets `python_requires=">=3.10"` and `install_requires=['Django>=4.2']`, and its classifier list runs from `Framework :: Django :: 4.2` through `5.0`, `5.1` and `5.2`, with Python classifiers for 3.10 to 3.14.
So the installable artifact requires Python 3.10 and Django 4.2, while the prose still advertises Django 3.2. If you are on Django 3.2 today, pip will resolve an older version of this package rather than the current one, which is the correct behaviour but not what the README implies. Treat the classifiers as the source of truth, since that is what the PyPI badge and the resolver both read.
The Python floor is at least consistent internally. Classifiers stop at 3.14 and `python_requires` starts at 3.10, so the matrix and the constraint agree with each other even where the README disagrees.
setuptools_scm versioning and JazzBand's maintainer model
Version numbers come from tags rather than a hardcoded string. `setup.py` passes `use_scm_version={"version_scheme": "post-release"}` with `setup_requires=["setuptools_scm"]`, which means the installed version is derived from git history at build time. The consequence for a user is straightforward and occasionally annoying: installing from a git checkout rather than from PyPI can produce a version string with a local segment, and a build without proper git metadata can fail outright.
The author field says Carl Meyer with an odddbird.net address, and the maintainer field says JazzBand. That pairing is the whole governance story in two lines. JazzBand is a collective of maintainers who take shared responsibility for a set of Python packages, which is a different arrangement from a single author field and explains why the repository carries `CODE_OF_CONDUCT.md`, an `AUTHORS.rst` file and a `CONTRIBUTING.rst` rather than a single-person contribution policy.
The licensing follows the same collective pattern. `setup.py` declares `license="BSD"` and a `BSD License` classifier, while the repository metadata reports BSD-3-Clause, and `LICENSE.txt` sits at the root. Those agree, which is more than can be said for the Django version range.
A test and docs toolchain you can run from the Makefile
The `Makefile` is the part of this repository that tells you how the project is actually worked on, and it is more informative than the README. The default target is `all: init docs test`, and `init` creates a virtualenv, installs the package in editable mode with pip, then installs tox, coverage and Sphinx, writing a stamp file so the setup runs once.
test: init
$(VENV)/bin/coverage erase
$(VENV)/bin/tox
$(VENV)/bin/coverage htmlMulti-database testing is handled with Docker rather than a hosted service. The `docker-compose.yml` at the root brings up a single `postgres:14-alpine` container with `POSTGRES_HOST_AUTH_METHOD: trust`, a database named `modelutils` and port 5432 published. Trust authentication is fine for a throwaway CI container and would be a problem anywhere else.
Alongside that there is a `tox.ini` for the version matrix, `requirements-test.txt` separate from `requirements.txt`, a `.coveragerc`, `mypy.ini` and `requirements-mypy.txt`, and a `.pre-commit-config.yaml`. `translations.py` at the root is a small script wrapping Django's `makemessages` and `compilemessages`, wired up as the `messages` and `compilemessages` targets, which is how the package ships localized documentation.
A 5.0 release about typing, and a busy issue tracker
Version 5.0.0 landed on 2024-09-04 and its release notes are dominated by one contributor's typing work, with the maintainer explicitly thanking @mthuurne for the effort. The individual changes read like a typing audit: modernize how keyword-only arguments are implemented, forward additional arguments to `contribute_to_class()`, modernize property definitions in `SplitText`, and clean up the code handling the `factory` argument on `UrlsafeTokenField`.
That is a sensible way to spend a major version. Adding type hints to a library people use through model class bodies means every downstream project's own type checker now runs against your annotations, so a major bump is the right place to do it. There is a `5.0b0` beta from 2024-06-19 whose release body is a single line, Beta release for testing the type hints, which confirms the intent.
An earlier release, 4.5.1 from 2024-05-02, is a single-entry release removing `JoinQueryset.get_quoted_query()`, a reminder that this package does remove APIs. The repository has 125 open issues against 2,759 stars, which is a high ratio for a package with no runtime dependencies, though the mixin surface is broad enough to generate feature requests rather than bug reports. The last push was on 2026-09-21, so the mixins are still being maintained against current Django releases even though the last tagged version is nearly two years old.
Editorial conclusion
django-model-utils earns its place by being the code you would otherwise copy between projects, kept typed and kept tested. The mixins are individually small and deliberately non-magical, which means you can read one and understand it in a minute. Two practical notes before you adopt it: the README's stated Django 3.2 support no longer matches what `setup.py` installs, and the package's own documentation lives on Read the Docs rather than in the repository. Add it when you find yourself writing a `created` and `modified` pair for the third time.
Frequently asked questions
Which Django versions does django-model-utils support?
The README says Django 3.2 and later, but `setup.py` is stricter: `install_requires` asks for Django 4.2 or newer and `python_requires` asks for Python 3.10. The classifiers list Django 4.2 through 5.2 and Python 3.10 through 3.14. The packaging metadata is what pip reads, so treat that as the real support range.
Why does installing from git give a strange version number?
The package versions itself from git tags rather than a hardcoded string, using `use_scm_version` with a post-release scheme and `setuptools_scm`. That means a build from a checkout can produce a version with a local segment, and a checkout without git metadata can fail to build. Install from PyPI unless you specifically need an unreleased commit.
Who maintains django-model-utils?
JazzBand, a collective of maintainers who share responsibility for a group of Python packages. `setup.py` lists Carl Meyer as the original author with an odddbird.net address, and JazzBand as the maintainer. The repository carries a code of conduct, an AUTHORS file and a contributing guide, which is the usual shape for that arrangement.
How do I run the tests for django-model-utils?
Run `make test`, which creates a virtualenv, installs the package editable, then runs coverage erase, tox and coverage html. A Postgres container is needed for the matrix and `docker-compose.yml` provides one on port 5432 with a database called modelutils and trust authentication. Sphinx is installed too, so `make docs` works from the same environment.
Is the documentation for django-model-utils in the repository?
No. The README points to django-model-utils.readthedocs.io and the repository itself holds only a short README, a changelog and the source. The `docs/` directory is present for building that site locally with `make docs`, so the content lives in the repository but the reading experience is the hosted documentation.
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/jazzband-django-model-utils)