Skip to main content

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 VersionedModel objects) to any previous version.
  • Audit trail to see who changed what and when.
  • Handles nested ForeignKey and ManyToMany relationships for VersionedModel objects.

🚀 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.CrequestMiddleware is optional, but recommended. If present, VersionedModel will attempt to use CrequestMiddleware.get_request().user when user is not provided to save(), delete(), restore(), or rollback().

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 ContentType framework. Ensure django.contrib.contenttypes is enabled.
  • crequest.middleware.CrequestMiddleware is helpful for automatically populating user when saving versions from request-handling code; without it you should pass user= explicitly when you want to track who made a change.
  • django-admin-rangefilter enhances the admin by letting you filter version history by created_at date range.
  • For large datasets, consider indexing VersionControl fields you query often (such as object_id, content_type and data_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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_versioning-0.1.7.tar.gz (12.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_versioning-0.1.7-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

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

Hashes for django_versioning-0.1.7.tar.gz
Algorithm Hash digest
SHA256 d89d9e2775ff28f0fa9c7ec2c60c77e555bc8fba8b4c4be7e40b632ec0fdccea
MD5 e7792563c9c74332d6c48d836e9e45a5
BLAKE2b-256 1ec30224afc8cd3702539b30fdee3f00f062e353e6b9b6ec49a3f1ed9b287abf

See more details on using hashes here.

File details

Details for the file django_versioning-0.1.7-py3-none-any.whl.

File metadata

File hashes

Hashes for django_versioning-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 59f94609d73eab4b891db0de70c06fb00b2adcc89dfb19304505c300489212b3
MD5 8dfc87f049c9402371d4f9f9c0a2c13a
BLAKE2b-256 c8a9f0cf79eef741818a357cb81adfd36d2129f2f56814e19cd1b9f6b0074972

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page