Code Monkey home page Code Monkey logo

django-fullhistory's Introduction

To install:

sudo setup.py install

*add fullhistory middleware

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.doc.XViewMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
    'fullhistory.fullhistory.FullHistoryMiddleware',
)

* add fullhistory to installed apps:

INSTALLED_APPS = (
    'fullhistory',
)

* In your models.py, select the models you want to have fullhistory:

from fullhistory import register_model
register_model(SKU)
register_model(Order)
register_model(OrderItem)

Known Issues
 * Many to Many fields don't automatically record changes. Adjustments have been made in the admin model to compensate for this. However, changes done outside the admin that are not adjusted may exhibit a delayed recording. (Django Ticket #5390)
 * Files are not preserved, just their path.
 * (Django 1.0 only) The FullHistory field does not work as expected with Non-abstract model inheritence, primarly for objects the have inherited another's FullHistory field (Django Ticket #9546)
 * FullHistory truncates microseconds for DateTimeFields
 * DateTimeFields are deserialized as strings
 * Model proxies is inefficient, likely to create duplicate history entries. Will be fixed.

Notes
 * Records for models that use Non-abstract inheritence are stored seperately per table. This has to do with the current implementation of serialization in Django. Also parent tables are capable of being independently modified of their inherited children.
 * Fullhistory for Non-abstract Model inheritence is slightly less performant as it follows the parental field.
 * QuerySet methods delete() and update() do not trigger signals and thus are outside of fullhistory
 * FullHistory Admin functionality is limited in Django 1.0


django-fullhistory's People

Contributors

zbyte64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-fullhistory's Issues

Duplicate revision numbers causing IntegrityErrors

There are two ways duplicate revision numbers can be created, which causes the following error:

IntegrityError: duplicate key value violates unique constraint "fullhistory_fullhistory_revision_key"
DETAIL:  Key (revision, content_type_id, object_id)=(6869, 19, 1840) already exists.

The revision number is calculated in FullHistory.save():

if not self.pk:
    self.revision = len(FullHistory.objects.filter(content_type=self.content_type, object_id=self.object_id))
  1. If another FullHistory model is inserted into the database after the revision number has been calculated, but before inserting the current model.

  2. If old revisions are removed, for instance if your revision history becomes too large to store.

A solution for number 2 would be to find the maximum revision number and increment it:

max_revision = FullHistory.objects.filter(content_type=self.content_type, object_id=self.object_id).aggregate(rev=Max('revision'))['rev']
                self.revision = (max_revision + 1) if max_revision is not None else 0

The hacky solution currently employed for number 1 is to retry with a new revision number if an IntegrityError is raised.

Traceback of the error in case it helps:

File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/base.py", line 570, in save_base
    created=(not record_exists), raw=raw, using=using)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 172, in send
    response = receiver(signal=self, sender=sender, **named)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/fullhistory/fullhistory.py", line 124, in save_history_signal
    create_history(instance, created and 'C' or 'U')

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/fullhistory/fullhistory.py", line 79, in create_history
    fh.save()

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/fullhistory/models.py", line 187, in save
    return super(FullHistory, self).save(*args, **kwargs)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/base.py", line 553, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/manager.py", line 195, in _insert
    return insert_query(self.model, values, **kwargs)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/query.py", line 1436, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 791, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)

  File "/var/local/polaris/env/rest/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 44, in execute
    return self.cursor.execute(query, args)

IntegrityError: duplicate key value violates unique constraint "fullhistory_fullhistory_revision_key"
DETAIL:  Key (revision, content_type_id, object_id)=(6869, 19, 1840) already exists.

Side note: Passing a QuerySet into len will execute a query returning all matching rows. Using .count() translates into an SQL COUNT query and should be quicker.

Thanks for reading :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.