diff --git a/auditlog/diff.py b/auditlog/diff.py index e6271497..833db01f 100644 --- a/auditlog/diff.py +++ b/auditlog/diff.py @@ -2,7 +2,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.db.models import Model, NOT_PROVIDED, DateTimeField from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str def track_field(field): @@ -17,12 +17,16 @@ def track_field(field): :rtype: bool """ from auditlog.models import LogEntry + # Do not track many to many relations if field.many_to_many: return False # Do not track relations to LogEntry - if getattr(field, 'remote_field', None) is not None and field.remote_field.model == LogEntry: + if ( + getattr(field, "remote_field", None) is not None + and field.remote_field.model == LogEntry + ): return False return True @@ -65,7 +69,7 @@ def get_field_value(obj, field): value = field.default if field.default is not NOT_PROVIDED else None else: try: - value = smart_text(getattr(obj, field.name, None)) + value = smart_str(getattr(obj, field.name, None)) except ObjectDoesNotExist: value = field.default if field.default is not NOT_PROVIDED else None @@ -108,16 +112,26 @@ def model_instance_diff(old, new): model_fields = None # Check if fields must be filtered - if model_fields and (model_fields['include_fields'] or model_fields['exclude_fields']) and fields: + if ( + model_fields + and (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']] + 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']] + 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: @@ -125,7 +139,7 @@ def model_instance_diff(old, new): new_value = get_field_value(new, field) if old_value != new_value: - diff[field.name] = (smart_text(old_value), smart_text(new_value)) + diff[field.name] = (smart_str(old_value), smart_str(new_value)) if len(diff) == 0: diff = None diff --git a/auditlog/receivers.py b/auditlog/receivers.py index 25a62285..ac98c7f5 100644 --- a/auditlog/receivers.py +++ b/auditlog/receivers.py @@ -13,11 +13,13 @@ def log_create(sender, instance, created, **kwargs): if created: changes = model_instance_diff(None, instance) - log_entry = LogEntry.objects.log_create( - instance, - action=LogEntry.Action.CREATE, - changes=json.dumps(changes), - ) + # Log an entry only if there are changes + if changes: + log_entry = LogEntry.objects.log_create( + instance, + action=LogEntry.Action.CREATE, + changes=json.dumps(changes), + ) def log_update(sender, instance, **kwargs): @@ -54,8 +56,10 @@ def log_delete(sender, instance, **kwargs): if instance.pk is not None: changes = model_instance_diff(instance, None) - log_entry = LogEntry.objects.log_create( - instance, - action=LogEntry.Action.DELETE, - changes=json.dumps(changes), - ) + # Log an entry only if there are changes + if changes: + log_entry = LogEntry.objects.log_create( + instance, + action=LogEntry.Action.DELETE, + changes=json.dumps(changes), + ) diff --git a/auditlog_tests/models.py b/auditlog_tests/models.py index 4eda784f..9671fe97 100644 --- a/auditlog_tests/models.py +++ b/auditlog_tests/models.py @@ -85,7 +85,7 @@ class SimpleIncludeModel(models.Model): A simple model used for register's include_fields kwarg """ - label = models.CharField(max_length=100) + label = models.CharField(null=True, max_length=100) text = models.TextField(blank=True) history = AuditlogHistoryField() diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index 9993f767..60d6f18e 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -200,6 +200,20 @@ def test_register_include_fields(self): sim.save() self.assertTrue(sim.history.count() == 2, msg="There are two log entries") + # Create with text, ignore + sim = SimpleIncludeModel(text="Looong text") + sim.save() + self.assertTrue(sim.history.count() == 0, msg="There are no log entries") + + # Delete, ignore + self.assertTrue( + LogEntry.objects.count() == 2, msg="There are two log entries total" + ) + sim.delete() + self.assertTrue( + LogEntry.objects.count() == 2, msg="No log entry added after delete" + ) + class SimpeExcludeModelTest(TestCase): """Log only changes that are not in exclude_fields"""