Skip to main content

Django Chronicle is an implementation of the slowly changing dimensions type 4 which uses database triggers.

How to use?

  1. Create a custom revision model. e.g.

    from chronicle.models import AbstractRevision
    
    class Revision(AbstractRevision):
        user = models.ForeignKey(settings.AUTH_USER_MODEL)
        created = models.DateTimeField(auto_now_add=True)
    
  2. Set settings.REVISION_MODEL to point to your revision model. e.g.

    REVISION_MODEL = 'revision.Revision'
    
  3. Let your models inherit from HistoryMixin e.g.

    from chronicle.models import HistoryMixin
    from django.db import models
    
    class Food(HistoryMixin, models.Model):
        name = models.CharField(max_length=50)
    
  4. Create all the migrations and run them:

    $ manage.py makemigrations
    $ manage.py migrate
    

    That should create all the _history tables for your models that inherit from the HistoryMixin.

  5. Create the database triggers

    $ manage.py create_history_triggers
    

Now every change to your models should be logged in the _history tables and you can access the model history via the History model which becomes a field of the original class.

Example usage:

# create
food = Food('Carot')
food.save()
assert(Food.History.objects.filter(id=food.id).count() == 1)

# update
food.name = 'Carrot'
food.save()
assert(Food.History.objects.filter(id=food.id).count() == 2)

# delete
food.delete()
assert(Food.History.objects.filter(id=food.id).count() == 3)

Why database triggers?

The obvious choice to implement model history would be to connect a signal handler to the post_save and post_delete signal. This has some rather huge downsides:

1.) QuerySet.update() and a lot of other QuerySet methods do not emit any signals. Having to limit the code to only use save() can be a rather huge performance problem depending on the type of application.

2.) There is a rather large performance impact when creating the history via the Django ORM. A single QuerySet.update() call could result in hundreds or thousands of inserts. While this could mostly be solved using the Manager.bulk_create method a database trigger is a lot faster as there is no extra database roundtrip required.

3.) This works for any kind of raw query - even outside of the Django ORM - as long as the chronicle.revision_id session variable is properly set.

The only real downside is the DB compatibility. Right now this package only supports the PostgreSQL database engine.

How to issue queries without the Django ORM?

Create a revision by inserting a row into the revision table and set the chronicle.revision_id session variable like so:

SET chronicle.revision_id = 42; -- replace 42 by the actual revision id

Once you have made all changes to your models don't forget to reset the session variable. Otherwise you might reuse the same revision by accident in the same DB session:

SET chronicle.revision_id TO DEFAULT;

Release files for django-chronicle 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-chronicle 0.2.0
File Size Uploaded
django_chronicle-0.2.0.tar.gz 12.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-chronicle 0.2.0
File Interpreter ABI Platform
django_chronicle-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.4 kB

Release files / django_chronicle-0.2.0.tar.gz

Download URL django_chronicle-0.2.0.tar.gz
Size 12.7 kB
Tags Source
SHA-256 checksum
How to use checksums
05d8370741493d01587ef6384844c4fecccb13f91079385b07d6453c0ec11dd1
BLAKE2b-256 checksum
How to use checksums
ec120ec9869d45ef988aaa4f678b1ef251f6310c8c6103cee8fae1cb201561f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.7.1 CPython/3.10.12 Linux/5.15.0-97-generic

Release files / django_chronicle-0.2.0-py3-none-any.whl

Download URL django_chronicle-0.2.0-py3-none-any.whl
Size 10.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8b1cab138e7cc1e148d246a80f278650af26dcff93feedee78cb08342954c1f9
BLAKE2b-256 checksum
How to use checksums
f2dd3369a8aeb927132fea0cc00c4eae893748de282189f3ff0c9d3d8025df96
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.7.1 CPython/3.10.12 Linux/5.15.0-97-generic

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

0.0.0

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page