mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-05-17 03:51:07 +00:00
Merge pull request #12 from vittoriozamboni/limitfields
Added include_fields and exclude_fields kwargs to register method
This commit is contained in:
commit
4fd8387df0
6 changed files with 106 additions and 12 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,12 +22,19 @@ 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.')
|
||||
|
|
@ -43,7 +50,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 +77,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()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,30 @@ class ManyRelatedModel(models.Model):
|
|||
history = AuditlogHistoryField()
|
||||
|
||||
|
||||
class SimpleIncludeModel(models.Model):
|
||||
"""
|
||||
A simple model used for register's include_fields kwarg
|
||||
"""
|
||||
|
||||
label = models.CharField(max_length=100)
|
||||
text = models.TextField(blank=True)
|
||||
|
||||
history = AuditlogHistoryField()
|
||||
|
||||
|
||||
class SimpleExcludeModel(models.Model):
|
||||
"""
|
||||
A simple model used for register's exclude_fields kwarg
|
||||
"""
|
||||
|
||||
label = models.CharField(max_length=100)
|
||||
text = models.TextField(blank=True)
|
||||
|
||||
history = AuditlogHistoryField()
|
||||
|
||||
|
||||
auditlog.register(SimpleModel)
|
||||
auditlog.register(AltPrimaryKeyModel)
|
||||
auditlog.register(ProxyModel)
|
||||
auditlog.register(SimpleIncludeModel, include_fields=['label', ])
|
||||
auditlog.register(SimpleExcludeModel, exclude_fields=['label', ])
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ from django.http import HttpResponse
|
|||
from django.test import TestCase, RequestFactory
|
||||
from auditlog.middleware import AuditlogMiddleware
|
||||
from auditlog.models import LogEntry
|
||||
from testapp.models import SimpleModel, AltPrimaryKeyModel, ProxyModel
|
||||
from testapp.models import SimpleModel, AltPrimaryKeyModel, ProxyModel, \
|
||||
SimpleIncludeModel, SimpleExcludeModel
|
||||
|
||||
|
||||
class SimpleModelTest(TestCase):
|
||||
|
|
@ -139,3 +140,41 @@ class MiddlewareTest(TestCase):
|
|||
|
||||
# Validate result
|
||||
self.assertFalse(pre_save.has_listeners(LogEntry))
|
||||
|
||||
|
||||
class SimpeIncludeModelTest(TestCase):
|
||||
"""Log only changes in include_fields"""
|
||||
|
||||
def test_register_include_fields(self):
|
||||
sim = SimpleIncludeModel(label='Include model', text='Looong text')
|
||||
sim.save()
|
||||
self.assertTrue(sim.history.count() == 1, msg="There is one log entry")
|
||||
|
||||
# Change label, record
|
||||
sim.label = 'Changed label'
|
||||
sim.save()
|
||||
self.assertTrue(sim.history.count() == 2, msg="There are two log entries")
|
||||
|
||||
# Change text, ignore
|
||||
sim.text = 'Short text'
|
||||
sim.save()
|
||||
self.assertTrue(sim.history.count() == 2, msg="There are two log entries")
|
||||
|
||||
|
||||
class SimpeExcludeModelTest(TestCase):
|
||||
"""Log only changes that are not in exclude_fields"""
|
||||
|
||||
def test_register_exclude_fields(self):
|
||||
sem = SimpleIncludeModel(label='Exclude model', text='Looong text')
|
||||
sem.save()
|
||||
self.assertTrue(sem.history.count() == 1, msg="There is one log entry")
|
||||
|
||||
# Change label, ignore
|
||||
sem.label = 'Changed label'
|
||||
sem.save()
|
||||
self.assertTrue(sem.history.count() == 2, msg="There are two log entries")
|
||||
|
||||
# Change text, record
|
||||
sem.text = 'Short text'
|
||||
sem.save()
|
||||
self.assertTrue(sem.history.count() == 2, msg="There are two log entries")
|
||||
|
|
|
|||
Loading…
Reference in a new issue