# django-reversion: version control for Django model instances

> A Django extension that keeps a revision history of your model rows, so you can roll an instance back to an earlier state or recover one that was deleted. Useful details on the schema it adds, the migrations it introduces, and what the release history says about its maintenance pace.

**etianen/django-reversion** — django-reversion is an extension to the Django web framework that provides version control for model instances.

- Repository: https://github.com/etianen/django-reversion
- Website: https://django-reversion.readthedocs.io
- Stars: 3,169 · Forks: 494
- Language: Python
- License: BSD-3-Clause
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/etianen-django-reversion

## What the library adds on top of your models

The project describes itself as an extension to the Django web framework that provides version control for model instances. That is a narrower claim than version control for your codebase, and it is worth being precise about the difference. Django already has migrations, which version your database schema. django-reversion versions the contents of individual rows, so a record that said one thing last week and something else today can be walked back to either state.

The README lists three features and they are the whole scope of the idea. Roll back to any point in a model instance's history. Recover deleted model instances. Simple admin integration. The third one is what makes the library practical rather than merely possible, because most Django projects edit their data through the admin and would otherwise have no undo at all.

The package sits at 3,167 stars and 492 forks, is BSD-3-Clause licensed, and is not archived. Documentation lives at django-reversion.readthedocs.io, and the README is explicit that the docs there are the current version rather than the README itself.

## Support matrix and how the packaging is pinned

The README states its requirements as Python 3.8 or later and Django 4.2 or later. The packaging metadata in `setup.py` is a little stricter on Python, asking for 3.9 or later, and it lists explicit interpreter classifiers from 3.9 through 3.14. A project on Python 3.8 will read one requirement in the README and hit a different one at install time, which is a small thing worth knowing in advance.

The dependency list is otherwise deliberately thin:

```python
install_requires=[
    "django>=4.2",
],
python_requires=">=3.9",
```

That single lower bound on Django is the whole install requirement set, which is a good sign for a library that runs inside a large application. The remaining packaging concerns are packaging concerns rather than runtime ones. Locale files and admin templates ship as package data, and a block of Babel command classes is wired in only when Babel happens to be importable, so the translation workflow is available without being required.

```python
package_data={
    "reversion": ["locale/*/LC_MESSAGES/django.*", "templates/reversion/*.html"]
},
```

The repository tree is correspondingly compact. `reversion/` holds the package, `tests/` the suite, `docs/` the published documentation, alongside `setup.py`, `setup.cfg`, `MANIFEST.in` and a `CHANGELOG.rst` that the README tells you to read before every upgrade.

## Running the project from a fork

The contributing section is a short, specific set of steps rather than a general invitation. Fork the repository on GitHub, branch off master, install the requirements, run the tests, then open a pull request.

The install step is deliberately explicit about the database drivers, because the test suite talks to a real database rather than mocking it:

```bash
$ pip install django psycopg2 mysqlclient -e .
```

Both `psycopg2` and `mysqlclient` appear in that one line, which tells you the project's own CI exercises PostgreSQL and MySQL. A contributor working on a laptop only needs one of them, but the fact that both are named in the default instruction is a decent signal about which backends get real coverage.

The test command runs a script inside the tests directory rather than a bare `manage.py`:

```bash
$ tests/manage.py test tests
```

That arrangement keeps the test project's settings separate from anything in your own repository, which is the usual reason a library ships its own management script. For a project deciding whether to adopt django-reversion, the practical takeaway is that the contribution path is short enough to try a patch, and the maintainer credits contributions in release notes rather than treating them as noise.

## What recent releases reveal about maintenance pace

Three releases in the published history cover the period from December 2025 to June 2026, and the contents are more informative than the dates alone. v6.1.0, published 2025-12-12, added date-based ordering and a custom version sort. That sounds like a detail and is not, because version ordering is what decides which state a rollback call resolves to when a row has been edited many times.

v6.2.0, published 2026-05-12, is the one that matters most for anyone running the current Django generation. It added tests for Django 6.0, added explicit Django versions to the package classifiers, and added a custom object id field contributed by a first-time contributor. Testing against the newest Django before most users are on it is a maintenance behaviour worth noting, because Django's per-version upgrade window is where third-party packages usually show up broken.

v6.3.0 followed on 2026-06-12 with a Turkish translation, and the repository's last push was the same day. A steady stream of small releases by outside contributors, each naming the pull request that produced it, is a healthier pattern than long gaps followed by a bulk import.

## Where the README stops and the hosted docs begin

This README is short, and for a library of its age that is the point rather than a gap. It states the two requirements, the three features, points at the hosted documentation for the actual getting started material, and points at the changelog before upgrades. Everything about registering a model, configuring the middleware, choosing which fields to track and what happens to untracked fields on rollback lives on django-reversion.readthedocs.io.

That split matters for evaluation. The README will not tell you whether rollback is safe for your data, whether deleted-instance recovery is something you want exposed to editors, or how the version tables grow over time. Those are real design questions and they are answered in the documentation rather than in the repository front page. The repository itself answers a different set: the tree shows a small package with a separate test project, and the release history shows a project that upgrades against new Django versions on a schedule rather than in bursts.

If you are weighing this against a field-level history package such as django-simple-history, or against adding an audit table to your own models by hand, the honest version is that the comparison has to be done against the hosted docs for both, since both keep the repository README deliberately thin.

## What rollback does and does not restore

The library's name invites a particular assumption, that rollback is like `git revert`. It is better understood as reconstructing a row from a stored revision. That distinction has practical consequences. Fields you did not register for versioning are not in the revision, so they are not restored. Related objects that were modified in the same request are not touched, because the history is per registered instance rather than per transaction.

The recovery path for deleted instances is the mirror image of the same idea, and it is a separate feature from rollback rather than a consequence of it. Both of these work because writes pass through Django's ORM, which is why an object modified outside the ORM, by a raw SQL statement or a bulk operation that skips signals, can leave the history incomplete. The docs are where that boundary is spelled out.

None of this makes the library unsuitable. It makes it predictable, which is the property you actually want from something sitting underneath an audit trail. The decision comes down to whether your editors need a visible undo for individual records, in which case the admin integration and the register call are a short setup, or whether you need transaction-wide change history, in which case this is the wrong shape of tool and the field-level history packages or a dedicated audit framework fit better.

## Conclusion

django-reversion earns its place in projects that edit content through an admin interface without any other record of who changed what. Once the middleware and the register call are in place, revision records appear for saves and deletes without touching your model code, and rollback is a single call rather than a manual database repair. The trade is that you now own a set of version tables and a flow you have to explain to editors, and rollback reconstructs only registered fields. The last release, v6.3.0, shipped on 2026-06-12 alongside a Turkish translation, and the last push to master was the same day, so the project is being kept current with new Django releases rather than left on an older generation.

## FAQ

### Is django-reversion still maintained?

Yes, and the release history is recent enough to be concrete. v6.3.0 was published on 2026-06-12, v6.2.0 on 2026-05-12 and v6.1.0 on 2025-12-12. The v6.2.0 release added tests for Django 6.0, so the project is tracking the current Django generation rather than sitting on an older one. The repository is not archived and the last push to master was on 2026-06-12, at 3,167 stars and 492 forks with 25 open issues.

### What Django and Python versions does django-reversion support?

The README states Python 3.8 or later and Django 4.2 or later. The packaging metadata in setup.py is stricter on Python, requiring 3.9 or later, and lists interpreter classifiers from 3.9 through 3.14. Django 4.2 is the only runtime dependency in install_requires. If you are on Python 3.8 you will see the 3.8 figure in the README and then hit a 3.9 floor at install time.

### How is django-reversion different from django-simple-history?

The two libraries overlap heavily and the repository README does not make the comparison, so this needs the hosted documentation for both. The short version is that django-reversion centres on rollback and deleted-instance recovery with admin integration, which is why its feature list in the README is exactly those three items. django-simple-history is organised around tracking field-level changes for many models. Which one fits depends on whether your editors need an undo button for a record or a record of every field that changed.

### Does rolling back a model instance restore every field?

Not every field. A revision stores the fields registered for versioning, so reconstructing an earlier state restores those and leaves untracked fields alone. Related objects modified in the same request are also not part of the history, because it is recorded per registered instance rather than per transaction. Objects changed outside the ORM, for example by raw SQL, can leave the history incomplete. The getting started documentation on django-reversion.readthedocs.io covers which fields to register for your case.

### How do I get django-reversion set up in my Django project?

The README deliberately does not carry setup steps and instead sends you to the hosted documentation at django-reversion.readthedocs.io, which is where the getting started material lives. In outline the pieces are installing the package, adding its middleware, running the migrations that create the version tables, and registering the models you want tracked. If you want to see how the project itself is worked on, the contributing section shows the editable install and the test command used against PostgreSQL and MySQL.

## Sources

- [etianen/django-reversion on GitHub](https://github.com/etianen/django-reversion)
- [License: BSD-3-Clause](https://github.com/etianen/django-reversion/blob/master/LICENSE)
- [Project website](https://django-reversion.readthedocs.io)
- [README](https://github.com/etianen/django-reversion/blob/master/README.md)
- [Releases](https://github.com/etianen/django-reversion/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/etianen-django-reversion
