mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
Additional field for metadata
This commit is contained in:
commit
a31fb790f1
6 changed files with 83 additions and 4 deletions
|
|
@ -1 +1,2 @@
|
|||
Django>=1.7
|
||||
django-jsonfield>=0.9.13
|
||||
|
|
|
|||
3
setup.py
3
setup.py
|
|
@ -11,6 +11,7 @@ setup(
|
|||
author_email='janjelle@jjkester.nl',
|
||||
description='Audit log app for Django',
|
||||
install_requires=[
|
||||
'Django>=1.7'
|
||||
'Django>=1.7',
|
||||
'django-jsonfield>=0.9.13',
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import jsonfield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auditlog', '0002_auto_support_long_primary_keys'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='logentry',
|
||||
name='additional_data',
|
||||
field=jsonfield.fields.JSONField(null=True, blank=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -11,6 +11,8 @@ from django.utils.encoding import python_2_unicode_compatible, smart_text
|
|||
from django.utils.six import iteritems, integer_types
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from jsonfield import JSONField
|
||||
|
||||
|
||||
class LogEntryManager(models.Manager):
|
||||
"""
|
||||
|
|
@ -33,6 +35,10 @@ class LogEntryManager(models.Manager):
|
|||
if isinstance(pk, integer_types):
|
||||
kwargs.setdefault('object_id', pk)
|
||||
|
||||
get_additional_data = getattr(instance, 'get_additional_data', None)
|
||||
if callable(get_additional_data):
|
||||
kwargs.setdefault('additional_data', get_additional_data())
|
||||
|
||||
# Delete log entries with the same pk as a newly created model. This should only be necessary when an pk is
|
||||
# used twice.
|
||||
if kwargs.get('action', None) is LogEntry.Action.CREATE:
|
||||
|
|
@ -138,6 +144,7 @@ class LogEntry(models.Model):
|
|||
changes = models.TextField(blank=True, verbose_name=_("change message"))
|
||||
actor = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_("actor"))
|
||||
timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_("timestamp"))
|
||||
additional_data = JSONField(blank=True, null=True, verbose_name=_("additional data"))
|
||||
|
||||
objects = LogEntryManager()
|
||||
|
||||
|
|
|
|||
|
|
@ -82,11 +82,36 @@ class SimpleExcludeModel(models.Model):
|
|||
history = AuditlogHistoryField()
|
||||
|
||||
|
||||
class AdditionalDataIncludedModel(models.Model):
|
||||
"""
|
||||
A model where get_additional_data is defined which allows for logging extra
|
||||
information about the model in JSON
|
||||
"""
|
||||
|
||||
label = models.CharField(max_length=100)
|
||||
text = models.TextField(blank=True)
|
||||
related = models.ForeignKey(SimpleModel)
|
||||
|
||||
history = AuditlogHistoryField()
|
||||
|
||||
def get_additional_data(self):
|
||||
"""
|
||||
Returns JSON that captures a snapshot of additional details of the
|
||||
model instance. This method, if defined, is accessed by auditlog
|
||||
manager and added to each logentry instance on creation.
|
||||
"""
|
||||
object_details = {
|
||||
'related_model_id': self.related.id,
|
||||
'related_model_text': self.related.text
|
||||
}
|
||||
return object_details
|
||||
|
||||
auditlog.register(SimpleModel)
|
||||
auditlog.register(AltPrimaryKeyModel)
|
||||
auditlog.register(ProxyModel)
|
||||
auditlog.register(RelatedModel)
|
||||
auditlog.register(ManyRelatedModel)
|
||||
auditlog.register(ManyRelatedModel.related.through)
|
||||
auditlog.register(SimpleIncludeModel, include_fields=['label', ])
|
||||
auditlog.register(SimpleExcludeModel, exclude_fields=['text', ])
|
||||
auditlog.register(SimpleIncludeModel, include_fields=['label'])
|
||||
auditlog.register(SimpleExcludeModel, exclude_fields=['text'])
|
||||
auditlog.register(AdditionalDataIncludedModel)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from django.test import TestCase, RequestFactory
|
|||
from auditlog.middleware import AuditlogMiddleware
|
||||
from auditlog.models import LogEntry
|
||||
from auditlog_tests.models import SimpleModel, AltPrimaryKeyModel, ProxyModel, \
|
||||
SimpleIncludeModel, SimpleExcludeModel, RelatedModel, ManyRelatedModel
|
||||
SimpleIncludeModel, SimpleExcludeModel, RelatedModel, ManyRelatedModel, AdditionalDataIncludedModel
|
||||
|
||||
|
||||
class SimpleModelTest(TestCase):
|
||||
|
|
@ -192,3 +192,28 @@ class SimpeExcludeModelTest(TestCase):
|
|||
sem.text = 'Short text'
|
||||
sem.save()
|
||||
self.assertTrue(sem.history.count() == 2, msg="There are two log entries")
|
||||
|
||||
|
||||
class AdditionalDataModelTest(TestCase):
|
||||
"""Log additional data if get_additional_data is defined in the model"""
|
||||
|
||||
def test_model_without_additional_data(self):
|
||||
obj_wo_additional_data = SimpleModel.objects.create(text='No additional '
|
||||
'data')
|
||||
obj_log_entry = obj_wo_additional_data.history.get()
|
||||
self.assertIsNone(obj_log_entry.additional_data)
|
||||
|
||||
def test_model_with_additional_data(self):
|
||||
related_model = SimpleModel.objects.create(text='Log my reference')
|
||||
obj_with_additional_data = AdditionalDataIncludedModel(
|
||||
label='Additional data to log entries', related=related_model)
|
||||
obj_with_additional_data.save()
|
||||
self.assertTrue(obj_with_additional_data.history.count() == 1,
|
||||
msg="There is 1 log entry")
|
||||
log_entry = obj_with_additional_data.history.get()
|
||||
self.assertIsNotNone(log_entry.additional_data)
|
||||
extra_data = log_entry.additional_data
|
||||
self.assertTrue(extra_data['related_model_text'] == related_model.text,
|
||||
msg="Related model's text is logged")
|
||||
self.assertTrue(extra_data['related_model_id'] == related_model.id,
|
||||
msg="Related model's id is logged")
|
||||
|
|
|
|||
Loading…
Reference in a new issue