django-versioning adds version history, diffs, rollbacks, and audit trails to Django models—fully integrated with the admin.
Project description
Django Version Control
A lightweight relational version control system for Django models. It records snapshots of model state (including FK and M2M relations), computes hashes to skip duplicate snapshots, stores human-readable diffs, supports soft-delete/restore, rollback, and generates audit trails.
✨ Features
- Automatic versioning of models that inherit
VersionedModel. - Tracks create, update, delete, restore, rollback actions.
- Stores full JSON snapshot of records in
VersionControl. - Computes SHA-256 hash of snapshots to avoid duplicate saves.
- Prepares human-readable diffs between versions.
- Supports soft delete and restore with user/timestamp metadata.
- Rollback a record (and related
VersionedModelobjects) to any previous version. - Audit trail to see who changed what and when.
- Handles nested ForeignKey and ManyToMany relationships for
VersionedModelobjects.
🚀 Installation
Install the package and (optionally) django-crequest to allow automatic request.user detection, plus django-admin-rangefilter to filter history by date in admin:
pip install django-versioning
pip install django-crequest
pip install django-admin-rangefilter
Add the app to INSTALLED_APPS in your settings.py:
INSTALLED_APPS = [
...
"django.contrib.contenttypes", # required
"version_control",
"rangefilter", # for DateRangeFilter in admin
]
If you installed django-crequest, add its middleware to your MIDDLEWARE list so the package can pick up the current request.user automatically when you don't explicitly pass user= to save/rollback/delete calls.
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
# Add crequest.middleware.CrequestMiddleware so VersionedModel can
# obtain the current request and user automatically.
"crequest.middleware.CrequestMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
...
]
Note:
crequest.middleware.CrequestMiddlewareis optional, but recommended. If present,VersionedModelwill attempt to useCrequestMiddleware.get_request().userwhenuseris not provided tosave(),delete(),restore(), orrollback().
Run migrations:
python manage.py makemigrations
python manage.py migrate
⚡ Quick Usage
1. Inherit from VersionedModel
from django.db import models
from version_control.models import VersionedModel
class Tag(VersionedModel):
name = models.CharField(max_length=100)
class Article(VersionedModel):
title = models.CharField(max_length=255)
content = models.TextField()
tags = models.ManyToManyField(Tag, blank=True)
2. Saving Versions
A version snapshot is created automatically when you call .save() on a VersionedModel. You can pass the user explicitly:
article.save(user=request.user)
If you omit user= and crequest.middleware.CrequestMiddleware is enabled, the package will try to resolve the current user from the active request.
3. Soft Delete & Restore
article.delete(user=request.user) # soft delete and record a tombstone snapshot
article.restore(user=request.user) # restore from soft-delete
To permanently delete a record (hard delete):
article.delete(user=request.user, hard=True)
4. Rollback
article.rollback(version_number=2, user=request.user)
5. Diffing Versions
diff = article.diff_versions(1, 3)
# Example: {"title": {"from": "First Post", "to": "Updated Post"}}
6. Audit Trail
history = article.audit_trail()
for entry in history:
print(entry["version"], entry["changed_by"], entry["changed_at"])
print(entry["changes"])
🛠️ Implementation Notes
- The package uses Django's
ContentTypeframework. Ensuredjango.contrib.contenttypesis enabled. crequest.middleware.CrequestMiddlewareis helpful for automatically populatinguserwhen saving versions from request-handling code; without it you should passuser=explicitly when you want to track who made a change.django-admin-rangefilterenhances the admin by letting you filter version history by created_at date range.- For large datasets, consider indexing
VersionControlfields you query often (such asobject_id,content_typeanddata_hash).
✅ Example Workflow
tag = Tag.objects.create(name="django")
article = Article.objects.create(title="Intro", content="Hello!", user=request.user)
article.tags.add(tag)
article.save(user=request.user)
# Update
article.content = "Updated content"
article.save(user=request.user)
# See audit trail
print(article.audit_trail())
📌 Compatibility
- Designed to work with Django 3.2+.
- Works with SQLite, Postgres, and MySQL (JSON fields will use Django's JSONField abstraction).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_versioning-0.1.7.tar.gz.
File metadata
- Download URL: django_versioning-0.1.7.tar.gz
- Upload date:
- Size: 12.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d89d9e2775ff28f0fa9c7ec2c60c77e555bc8fba8b4c4be7e40b632ec0fdccea
|
|
| MD5 |
e7792563c9c74332d6c48d836e9e45a5
|
|
| BLAKE2b-256 |
1ec30224afc8cd3702539b30fdee3f00f062e353e6b9b6ec49a3f1ed9b287abf
|
File details
Details for the file django_versioning-0.1.7-py3-none-any.whl.
File metadata
- Download URL: django_versioning-0.1.7-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59f94609d73eab4b891db0de70c06fb00b2adcc89dfb19304505c300489212b3
|
|
| MD5 |
8dfc87f049c9402371d4f9f9c0a2c13a
|
|
| BLAKE2b-256 |
c8a9f0cf79eef741818a357cb81adfd36d2129f2f56814e19cd1b9f6b0074972
|