Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dirty fields in django

Tags:

python

django

In my app i need to save changed values (old and new) when model gets saved. Any examples or working code?

I need this for premoderation of content. For example, if user changes something in model, then administrator can see all changes in separate table and then decide to apply them or not.

like image 752
Dmitry Shevchenko Avatar asked Sep 21 '08 11:09

Dmitry Shevchenko


People also ask

What are dirty fields?

Django Dirty Fields Dirty means that field in-memory and database values are different.

What are field types in Django?

Fields in Django are the data types to store a particular type of data. For example, to store an integer, IntegerField would be used. These fields have in-built validation for a particular data type, that is you can not store “abc” in an IntegerField. Similarly, for other fields.


2 Answers

I've found Armin's idea very useful. Here is my variation;

class DirtyFieldsMixin(object):     def __init__(self, *args, **kwargs):         super(DirtyFieldsMixin, self).__init__(*args, **kwargs)         self._original_state = self._as_dict()      def _as_dict(self):         return dict([(f.name, getattr(self, f.name)) for f in self._meta.local_fields if not f.rel])      def get_dirty_fields(self):         new_state = self._as_dict()         return dict([(key, value) for key, value in self._original_state.iteritems() if value != new_state[key]]) 

Edit: I've tested this BTW.

Sorry about the long lines. The difference is (aside from the names) it only caches local non-relation fields. In other words it doesn't cache a parent model's fields if present.

And there's one more thing; you need to reset _original_state dict after saving. But I didn't want to overwrite save() method since most of the times we discard model instances after saving.

def save(self, *args, **kwargs):     super(Klass, self).save(*args, **kwargs)     self._original_state = self._as_dict() 
like image 109
muhuk Avatar answered Sep 18 '22 09:09

muhuk


You haven't said very much about your specific use case or needs. In particular, it would be helpful to know what you need to do with the change information (how long do you need to store it?). If you only need to store it for transient purposes, @S.Lott's session solution may be best. If you want a full audit trail of all changes to your objects stored in the DB, try this AuditTrail solution.

UPDATE: The AuditTrail code I linked to above is the closest I've seen to a full solution that would work for your case, though it has some limitations (doesn't work at all for ManyToMany fields). It will store all previous versions of your objects in the DB, so the admin could roll back to any previous version. You'd have to work with it a bit if you want the change to not take effect until approved.

You could also build a custom solution based on something like @Armin Ronacher's DiffingMixin. You'd store the diff dictionary (maybe pickled?) in a table for the admin to review later and apply if desired (you'd need to write the code to take the diff dictionary and apply it to an instance).

like image 30
Carl Meyer Avatar answered Sep 22 '22 09:09

Carl Meyer