diff --git a/src/auditlog/diff.py b/src/auditlog/diff.py index c13efe5..2efc797 100644 --- a/src/auditlog/diff.py +++ b/src/auditlog/diff.py @@ -1,11 +1,14 @@ from django.db.models import Model -def model_instance_diff(old, new): +def model_instance_diff(old, new, **kwargs): """ Calculate the differences between two model instances. One of the instances may be None (i.e., a newly created model or deleted model). This will cause all fields with a value to have changed (from None). + """ + from auditlog.registry import auditlog + if not(old is None or isinstance(old, Model)): raise TypeError('The supplied old instance is not a valid model instance.') if not(new is None or isinstance(new, Model)): @@ -15,13 +18,29 @@ def model_instance_diff(old, new): if old is not None and new is not None: fields = set(old._meta.fields + new._meta.fields) + model_fields = auditlog.get_model_fields(new._meta.model) elif old is not None: fields = set(old._meta.fields) + model_fields = auditlog.get_model_fields(old._meta.model) elif new is not None: fields = set(new._meta.fields) + model_fields = auditlog.get_model_fields(new._meta.model) else: fields = set() + # Check if fields must be filtered + if (model_fields['include_fields'] or model_fields['exclude_fields']) and fields: + filtered_fields = [] + if model_fields['include_fields']: + filtered_fields = [field for field in fields + if field.name in model_fields['include_fields']] + else: + filtered_fields = fields + if model_fields['exclude_fields']: + filtered_fields = [field for field in filtered_fields + if field.name not in model_fields['exclude_fields']] + fields = filtered_fields + for field in fields: old_value = unicode(getattr(old, field.name, None)) new_value = unicode(getattr(new, field.name, None)) diff --git a/src/auditlog/models.py b/src/auditlog/models.py index 50cdf7e..a0f409e 100644 --- a/src/auditlog/models.py +++ b/src/auditlog/models.py @@ -38,7 +38,7 @@ class LogEntryManager(models.Manager): return self.create(**kwargs) return None - + def get_for_object(self, instance): """ Get log entries for the specified object. @@ -152,7 +152,7 @@ class LogEntry(models.Model): substrings.append(substring) return separator.join(substrings) - + class AuditlogHistoryField(generic.GenericRelation): """ diff --git a/src/auditlog/receivers.py b/src/auditlog/receivers.py index c9e6ea5..1fd8349 100644 --- a/src/auditlog/receivers.py +++ b/src/auditlog/receivers.py @@ -7,7 +7,7 @@ def log_create(sender, instance, created, **kwargs): """ Signal receiver that creates a log entry when a model instance is first saved to the database. - Direct use is discouraged, connect your model through auditlog.registry.registry instead. + Direct use is discouraged, connect your model through auditlog.registry.register instead. """ if created: changes = model_instance_diff(None, instance) @@ -23,7 +23,7 @@ def log_update(sender, instance, **kwargs): """ Signal receiver that creates a log entry when a model instance is changed and saved to the database. - Direct use is discouraged, connect your model through auditlog.registry.registry instead. + Direct use is discouraged, connect your model through auditlog.registry.register instead. """ if instance.pk is not None: try: @@ -48,7 +48,7 @@ def log_delete(sender, instance, **kwargs): """ Signal receiver that creates a log entry when a model instance is deleted from the database. - Direct use is discouraged, connect your model through auditlog.registry.registry instead. + Direct use is discouraged, connect your model through auditlog.registry.register instead. """ if instance.pk is not None: changes = model_instance_diff(instance, None) diff --git a/src/auditlog/registry.py b/src/auditlog/registry.py index ff078ca..5322edb 100644 --- a/src/auditlog/registry.py +++ b/src/auditlog/registry.py @@ -1,6 +1,5 @@ from django.db.models.signals import pre_save, post_save, post_delete from django.db.models import Model -from auditlog.receivers import log_create, log_update, log_delete class AuditLogModelRegistry(object): @@ -9,7 +8,8 @@ class AuditLogModelRegistry(object): """ def __init__(self, create=True, update=True, delete=True, custom=None): - self._registry = [] + from auditlog.receivers import log_create, log_update, log_delete + self._registry = {} self._signals = {} if create: @@ -22,15 +22,23 @@ class AuditLogModelRegistry(object): if custom is not None: self._signals.update(custom) - def register(self, model): + def register(self, model, **kwargs): """ Register a model with auditlog. Auditlog will then track mutations on this model's instances. + + Kwargs: + - `include_fields`: list of field names to include in diff + - `exclude_fields`: list of field names to exclude in diff """ if issubclass(model, Model): - self._registry.append(model) + self._registry[model] = { + 'include_fields': kwargs.get('include_fields', []), + 'exclude_fields': kwargs.get('exclude_fields', []), + } self._connect_signals(model) else: raise TypeError('Supplied model is not a valid model.') + print self._registry def contains(self, model): """ @@ -43,7 +51,7 @@ class AuditLogModelRegistry(object): Unregister a model with auditlog. This will not affect the database. """ try: - self._registry.pop(model) + del self._registry[model] except KeyError: pass else: @@ -70,5 +78,10 @@ class AuditLogModelRegistry(object): """ return (self.__class__, model, signal) + def get_model_fields(self, model): + return { + 'include_fields': self._registry[model]['include_fields'], + 'exclude_fields': self._registry[model]['exclude_fields'], + } auditlog = AuditLogModelRegistry()