Code

Changes between Version 5 and Version 6 of AuditTrail


Ignore:
Timestamp:
08/27/07 07:41:33 (7 years ago)
Author:
George Vilches <gav@…>
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AuditTrail

    v5 v6  
    6060ForeignKeys and OneToOneFields are now supported both for saving and accessing the audit data.  However, it does not archive the contents of the ForeignKey table for the appropriate entries at the same time, and will fail if the ForeignKey a given audit entry is related to is deleted (including if you're auditing the ForeignKey table as well, it does not have a way to link the two audit tables together). 
    6161 
     62== Tracking Extra Information == 
     63Sometimes you need to track more information than is available in just the model.  For instance, you may want to know who is performing the change on a particular entry, or track some sort of state information about the system.  AuditTrail now supports this through the concept of "track fields".  These can be specified on a per-model basis or a global basis, and the per-model options will stack with the global ones (but per-model options cannot override global ones currently).  Here's an example: 
     64 
     65{{{ 
     66def some_callback(instance): 
     67    return `random.randrange(1, 99)` + 'trackable_val' 
     68 
     69class Person(models.Model): 
     70    first_name = models.CharField(maxlength=255) 
     71    last_name = models.CharField(maxlength=255) 
     72    salary = models.PositiveIntegerField() 
     73    history = audit.AuditTrail(track_fields=(('extra_1', models.CharField(maxlength=50), 'hardcoded_value'), ('extra_2', models.CharField(maxlength=50), some_callback),)) 
     74 
     75    def __str__(self): 
     76        return "%s %s" % (self.first_name, self.last_name) 
     77}}} 
     78 
     79The track_fields is a tuple of 3-tuples.  The 3-tuples are structured {{{ (field_name, type_of_field, value) }}}.  `type_of_field` can be any currently functioning field type, although see the [#Caveats Caveats] for issues related to ForeignKeys.  `value` can be either a static value or a callback function, which will get called at the time of the save/delete.  This means that if you want to do something involving threadlocals at runtime (for getting things out of the request, for instance) you can do it via this callback. 
     80 
     81Assume we ran the example above with this new model.  You could then do the following: 
     82 
     83{{{ 
     84>>> p_hist = person.history.all() 
     85[<PersonAudit: John Public as of 2007-08-27 09:29:14>, <PersonAudit: John Public as of 2007-08-27 09:28:57>] 
     86>>> p_hist[0].extra_1 
     87'hardcoded_value' 
     88>>> p_hist[0].extra_2 
     89'27trackable_val' 
     90}}} 
     91 
     92Currently, you cannot filter on these trackable columns, this should be fixable. 
     93 
     94=== Global Track Fields === 
     95 
     96What if you have a field you want tracked on every model that supports history?  No problem!  In the root of your project, create a file called settings_audit.py, and put something like this in it: 
     97 
     98{{{ 
     99from django.db import models 
     100 
     101def callback_func_ptr2(original_instance): 
     102    import random 
     103    return `random.randrange(1, 99)` + 'hardcoded_global_2' 
     104 
     105# Populate the fields that every Audit model in this app will use. 
     106GLOBAL_TRACK_FIELDS = ( 
     107    ('global_1', models.CharField(maxlength=50), 'hardcoded_global_1'), 
     108    ('global_2', models.CharField(maxlength=20), callback_func_ptr2), 
     109) 
     110 
     111}}} 
     112 
     113GLOBAL_TRACK_FIELDS is set up exactly the same way as the track_fields option passed into AuditTrail, and has the same uses and limitations. 
     114 
    62115== Caveats == 
    63116This needs testing!  This has only been used in a few cases, there's plenty of possible room for strangeness.  It has specifically not been tested for things like safe (de-)serialization.