Ajout django_history_tables
authorcyril robert <Cyril Robert crobert@inverse.ca>
Wed, 20 Jan 2010 17:06:58 +0000 (12:06 -0500)
committercyril robert <Cyril Robert crobert@inverse.ca>
Wed, 20 Jan 2010 17:06:58 +0000 (12:06 -0500)
Apps/django_history_tables/LISEZMOI [new file with mode: 0644]
Apps/django_history_tables/__init__.py [new file with mode: 0644]
Apps/django_history_tables/changelog.txt [new file with mode: 0644]
Apps/django_history_tables/models.py [new file with mode: 0644]
Apps/django_history_tables/tests.py [new file with mode: 0644]
Apps/django_history_tables/views.py [new file with mode: 0644]

diff --git a/Apps/django_history_tables/LISEZMOI b/Apps/django_history_tables/LISEZMOI
new file mode 100644 (file)
index 0000000..547ebb0
--- /dev/null
@@ -0,0 +1,57 @@
+AUF - django_history_tables v0.1
+
+Cyril Robert <cyril.robert@auf.org>, 2010-01-20
+
+
+
+Introduction
+===============================================================================
+Application Django permettant de stocker les anciennes versions d'une instance
+dans une table d'historique separee.
+Projet original: http://code.google.com/p/django-history-tables/
+
+
+Dependances
+===============================================================================
+Python, Django
+
+
+Installation
+===============================================================================
+Faire et installer un package:
+    auf-make-deb django_history_tables
+    sudo dpkg -i django-history-tables*.deb
+
+
+Utilisation
+===============================================================================
+1. Ajouter "django_history_tables" dans INSTALLED_APPS
+2. Dans models.py, ajouter
+    from django_history_tables.models import *
+3. Pour chaque modele dont on veut un historique:
+
+    class Blabla (models.Model):
+        ...
+    class BlablaHistory(HistoryModel):
+        eggs = "eggs"
+        class History:
+            model = Blabla
+
+    def blablahistory_save (sender, instance, signal, *args, **kwargs):
+        history_model = BlablaHistory
+        history_save(sender, instance, signal, history_model, *args, **kwargs)
+
+    from django.db.models.signals import pre_save
+    pre_save.connect(blablahistory_save, sender=Blabla)
+4. Dans django_history_tables.views, il y a une methode instance_diff, qui 
+   permet de comparer 2 instances, elle n'est pas encore testee.
+
+
+Problemes connus
+===============================================================================
+
+
+Revisions
+===============================================================================
+
+Voir changelog.txt
diff --git a/Apps/django_history_tables/__init__.py b/Apps/django_history_tables/__init__.py
new file mode 100644 (file)
index 0000000..0098583
--- /dev/null
@@ -0,0 +1,2 @@
+import os
+os.environ['DJANGO_SETTINGS_MODULE'] = "settings"
diff --git a/Apps/django_history_tables/changelog.txt b/Apps/django_history_tables/changelog.txt
new file mode 100644 (file)
index 0000000..78bcd95
--- /dev/null
@@ -0,0 +1,4 @@
+django-history-tables (0.1) stable; urgency=low
+    * Initial version
+
+ -- Cyril Robert <cyril.robert@auf.org>  Tue, 19 Jan 2010 16:47:11 -0500
diff --git a/Apps/django_history_tables/models.py b/Apps/django_history_tables/models.py
new file mode 100644 (file)
index 0000000..f32b6c1
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from django.db import models
+from django.db.models.base import ModelBase
+from django.utils.translation import ugettext_lazy as _
+from copy import deepcopy
+
+import copy
+import datetime
+
+__all__ = ["HistoryModelBase", "HistoryModel", "history_save"] 
+
+
+class HistoryModelBase(ModelBase):
+    def __new__(cls, name, bases, dct):
+        new_class = ModelBase.__new__(cls, name, bases, dct)
+        if 'History' in dct:
+            history_model = dct['History'].model
+            for field in history_model._meta.fields:
+                if field.__class__.__name__ != 'AutoField':
+                    _field = deepcopy(field)
+                    if getattr(_field, 'unique', False):
+                        _field._unique = False
+                    rel = getattr(_field, 'rel', None)
+                    if rel and rel.related_name:
+                        rel.related_name = rel.related_name + "history"
+                    new_class.add_to_class(_field.name, _field)
+            for mm in history_model._meta.many_to_many:
+                _mm = deepcopy(mm)
+                if getattr(_mm, 'unique', False):
+                    _mm._unique = False
+                rel= getattr(_mm, 'rel', None)
+                if rel and rel.related_name:
+                    rel.related_name = rel.related_name + "history"    
+                if rel and rel.through:
+                    rel.through = rel.through + "History"  
+                else:      
+                    new_class.add_to_class(_mm.name, _mm)
+        return new_class
+    
+class HistoryModel(models.Model):
+    __metaclass__ = HistoryModelBase
+
+    history_datetime = models.DateTimeField(default=datetime.datetime.now)
+    history_objectid = models.PositiveIntegerField()
+    history_revision = models.PositiveIntegerField()
+    history_comment = models.CharField(max_length=1024, default="")
+
+    class Meta:
+        abstract = True
+
+def history_save(sender, instance, signal, history_model, *args, **kwargs):
+    if not instance.id:
+        # initial save, don't have to do anything :)
+        return
+    orginal = sender.objects.get(pk=instance.id)
+    history_obj = history_model()
+
+    history_obj.history_objectid = orginal.id
+    history_obj.history_revision = history_model.objects. \
+            filter(history_objectid = orginal.id).count() + 1
+    history_obj.history_comment = "pre_save history item <%s>" % \
+            (repr(orginal))
+    
+    for field in orginal._meta.fields:
+        if field.__class__.__name__ == 'AutoField':
+            continue
+        setattr(history_obj, field.name, getattr(orginal, field.name))
+    history_obj.save()
+    for mm in orginal._meta.many_to_many:
+        setattr(history_obj, mm.name, getattr(orginal, mm.name).all())
+    history_obj.save()
diff --git a/Apps/django_history_tables/tests.py b/Apps/django_history_tables/tests.py
new file mode 100644 (file)
index 0000000..2247054
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/Apps/django_history_tables/views.py b/Apps/django_history_tables/views.py
new file mode 100644 (file)
index 0000000..bc17409
--- /dev/null
@@ -0,0 +1,14 @@
+# Create your views here.
+from django.db.models import fields
+
+
+def instance_diff(instA, instB):
+    changes = {}
+
+    for f in instA._meta.fields:
+        if not isinstance(f, (fields.AutoField, fields.related.RelatedField)):
+            if f.value_from_object(instA) != f.value_from_object(instB):
+                changes[f.verbose_name] = (f.value_from_object(instA), \
+                        f.value_from_object(instB))
+
+    return changes