diff --git a/auditlog/models.py b/auditlog/models.py index 0b86318..255ad11 100644 --- a/auditlog/models.py +++ b/auditlog/models.py @@ -242,7 +242,21 @@ class LogEntryManager(models.Manager): "fields", self._get_applicable_model_fields(instance, model_fields) ) + # safeguard: if fields explicitly set → only use them + if "fields" in kwargs: + allowed_fields = set(kwargs["fields"]) + else: + allowed_fields = {f.name for f in instance._meta.fields} + instance_copy = self._get_copy_with_python_typed_fields(instance) + + # drop any deferred field not in allowed_fields + for f in instance_copy._meta.fields: + if f.name not in allowed_fields and f.name in getattr( + instance_copy, "deferred_fields", [] + ): + setattr(instance_copy, f.name, None) + data = dict( json.loads(serializers.serialize("json", (instance_copy,), **kwargs))[0] ) diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index 6764195..0f2f73e 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -24,6 +24,7 @@ from django.db.models import JSONField, Value from django.db.models.functions import Now from django.db.models.signals import pre_save from django.test import RequestFactory, TestCase, TransactionTestCase, override_settings +from django.test.utils import isolate_apps from django.urls import resolve, reverse from django.utils import dateformat, formats from django.utils import timezone as django_timezone @@ -137,6 +138,26 @@ class SimpleModelTest(TestCase): msg="Changes string is correct", ) + @isolate_apps("auditlog_tests") + def test_deletion_with_deferred_fields_does_not_crash(db): + from auditlog.models import LogEntry + from auditlog.registry import auditlog + + class Book(models.Model): + title = models.CharField(max_length=100) + description = models.TextField() + + class Meta: + app_label = "auditlog_tests" + + auditlog.register(Book, serialize_data=True) + + b = Book.objects.create(title="foo", description="bar") + b = Book.objects.defer("description").get(id=b.id) # defer a field + b.delete() + + assert LogEntry.objects.filter(object_pk=b.pk).exists() + def test_update_specific_field_supplied_via_save_method(self): obj = self.obj