Skip to main content

efficient model history using database triggers

Project description

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;

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-chronicle-0.1.0.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

django_chronicle-0.1.0-py2.py3-none-any.whl (9.5 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-chronicle-0.1.0.tar.gz.

File metadata

  • Download URL: django-chronicle-0.1.0.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Python-urllib/2.7

File hashes

Hashes for django-chronicle-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c3e7ad1a901d998e7d1decdd270a4e8fd7218e4d017661db1133df482a681e57
MD5 d5dadbf4200942be98aa1de32c291e20
BLAKE2b-256 13765ce51535675c29cd6a8a6bf43c99fd4cdb6a92335d230a965d6130440a44

See more details on using hashes here.

File details

Details for the file django_chronicle-0.1.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for django_chronicle-0.1.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 26456f709fb1be2c0ee1fe0d97ba0a44e55d3c005bdf9ae624b58227a3888bb3
MD5 8b8f74cdc620c7a3a4d8827b2287cf42
BLAKE2b-256 27f3314e82f9bf7707404559c1736e62d8a5f3bc01583d21909c5a7fe97f223e

See more details on using hashes here.

Supported by

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