mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
Fix None type mismatch in change detection (#763)
* Add test model and test cases for None value type mismatch - issue #750 @The-Alchemist * Fix None type mismatch in change detection
This commit is contained in:
parent
65ebec6663
commit
3051d230b9
4 changed files with 65 additions and 10 deletions
|
|
@ -73,15 +73,15 @@ def get_field_value(obj, field, use_json_for_changes=False):
|
|||
try:
|
||||
model_field = obj._meta.get_field(field.name)
|
||||
default = model_field.default
|
||||
if default is NOT_PROVIDED:
|
||||
return None
|
||||
|
||||
if callable(default):
|
||||
return default()
|
||||
|
||||
return default
|
||||
except AttributeError:
|
||||
return None
|
||||
default = NOT_PROVIDED
|
||||
|
||||
if default is NOT_PROVIDED:
|
||||
default = None
|
||||
elif callable(default):
|
||||
default = default()
|
||||
|
||||
return smart_str(default) if not use_json_for_changes else default
|
||||
|
||||
try:
|
||||
if isinstance(field, DateTimeField):
|
||||
|
|
|
|||
|
|
@ -442,6 +442,13 @@ class CustomMaskModel(models.Model):
|
|||
history = AuditlogHistoryField(delete_related=True)
|
||||
|
||||
|
||||
class NullableFieldModel(models.Model):
|
||||
time = models.TimeField(null=True, blank=True)
|
||||
optional_text = models.CharField(max_length=100, null=True, blank=True)
|
||||
|
||||
history = AuditlogHistoryField(delete_related=True)
|
||||
|
||||
|
||||
auditlog.register(AltPrimaryKeyModel)
|
||||
auditlog.register(UUIDPrimaryKeyModel)
|
||||
auditlog.register(ModelPrimaryKeyModel)
|
||||
|
|
@ -485,3 +492,4 @@ auditlog.register(
|
|||
mask_fields=["credit_card"],
|
||||
mask_callable="auditlog_tests.test_app.mask.custom_mask_str",
|
||||
)
|
||||
auditlog.register(NullableFieldModel)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from django.test import TestCase, override_settings
|
||||
from test_app.models import JSONModel, RelatedModel, SimpleModel
|
||||
from test_app.models import JSONModel, NullableFieldModel, RelatedModel, SimpleModel
|
||||
|
||||
from auditlog.models import LogEntry
|
||||
from auditlog.registry import AuditlogModelRegistry
|
||||
|
|
@ -147,3 +147,50 @@ class JSONForChangesTest(TestCase):
|
|||
all(v[1] is None for k, v in changes_dict.items()),
|
||||
'all values in the changes dict should None, not "None"',
|
||||
)
|
||||
|
||||
@override_settings(AUDITLOG_STORE_JSON_CHANGES=False)
|
||||
def test_nullable_field_with_none_not_logged(self):
|
||||
self.test_auditlog.register_from_settings()
|
||||
|
||||
obj = NullableFieldModel.objects.create(time=None, optional_text=None)
|
||||
changes_dict = obj.history.latest().changes_dict
|
||||
|
||||
# None → None should NOT be logged as a change
|
||||
self.assertNotIn("time", changes_dict)
|
||||
self.assertNotIn("optional_text", changes_dict)
|
||||
|
||||
@override_settings(AUDITLOG_STORE_JSON_CHANGES=False)
|
||||
def test_nullable_field_with_value_logged(self):
|
||||
self.test_auditlog.register_from_settings()
|
||||
|
||||
obj = NullableFieldModel.objects.create(optional_text="something")
|
||||
changes_dict = obj.history.latest().changes_dict
|
||||
|
||||
# None → "something" should be logged
|
||||
self.assertIn("optional_text", changes_dict)
|
||||
self.assertEqual(changes_dict["optional_text"], ["None", "something"])
|
||||
|
||||
@override_settings(AUDITLOG_STORE_JSON_CHANGES=True)
|
||||
def test_nullable_field_with_none_not_logged_json_mode(self):
|
||||
self.test_auditlog.register_from_settings()
|
||||
|
||||
obj = NullableFieldModel.objects.create(time=None, optional_text=None)
|
||||
changes_dict = obj.history.latest().changes_dict
|
||||
|
||||
# None → None should NOT be logged
|
||||
self.assertNotIn("time", changes_dict)
|
||||
self.assertNotIn("optional_text", changes_dict)
|
||||
|
||||
@override_settings(AUDITLOG_STORE_JSON_CHANGES=False)
|
||||
def test_nullable_field_update_none_to_value(self):
|
||||
self.test_auditlog.register_from_settings()
|
||||
|
||||
obj = NullableFieldModel.objects.create(optional_text=None)
|
||||
obj.optional_text = "updated"
|
||||
obj.save()
|
||||
|
||||
changes_dict = obj.history.latest().changes_dict
|
||||
|
||||
# None → "updated" should be logged
|
||||
self.assertIn("optional_text", changes_dict)
|
||||
self.assertEqual(changes_dict["optional_text"], ["None", "updated"])
|
||||
|
|
|
|||
|
|
@ -1358,7 +1358,7 @@ class RegisterModelSettingsTest(TestCase):
|
|||
|
||||
self.assertTrue(self.test_auditlog.contains(SimpleExcludeModel))
|
||||
self.assertTrue(self.test_auditlog.contains(ChoicesFieldModel))
|
||||
self.assertEqual(len(self.test_auditlog.get_models()), 33)
|
||||
self.assertEqual(len(self.test_auditlog.get_models()), 34)
|
||||
|
||||
def test_register_models_register_model_with_attrs(self):
|
||||
self.test_auditlog._register_models(
|
||||
|
|
|
|||
Loading…
Reference in a new issue