From ce58befd2747c302dcdd4633fbf59871c500784f Mon Sep 17 00:00:00 2001 From: Marco Marra Date: Mon, 12 Jan 2026 12:20:01 +0100 Subject: [PATCH] Add more test cases for changes_str. --- auditlog/models.py | 10 ++++------ auditlog_tests/tests.py | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/auditlog/models.py b/auditlog/models.py index a7c94a2..dd5158e 100644 --- a/auditlog/models.py +++ b/auditlog/models.py @@ -431,6 +431,8 @@ class AbstractLogEntry(models.Model): :param separator: The string to place between each field. :return: A readable string of the changes in this log entry. """ + substrings = [] + if all(isinstance(value, Sequence) for value in self.changes_dict.values()): substrings = [ "{field_name:s}{colon:s}{old:s}{arrow:s}{new:s}".format( @@ -440,20 +442,16 @@ class AbstractLogEntry(models.Model): arrow=arrow, new=values[1], ) - for field, values in self.changes_dict.items() + for field, values in sorted(self.changes_dict.items()) ] elif all( isinstance(value, dict) and value.get("type") == "m2m" for value in self.changes_dict.values() ): substrings = [ - f"{field}{colon}{value_dict['operation']} {value_dict['objects']}" + f"{field}{colon}{value_dict['operation']} {sorted(value_dict['objects'])}" for field, value_dict in self.changes_dict.items() ] - else: - substrings = [ - f"{field}{colon}{value}" for field, value in self.changes_dict.items() - ] return separator.join(substrings) diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index d991bef..2237e3a 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -131,6 +131,11 @@ class SimpleModelTest(TestCase): {"boolean": ["False", "True"]}, msg="The change is correctly logged", ) + self.assertEqual( + history.changes_str, + "boolean: False → True", + msg="Changes string is correct", + ) def test_update_specific_field_supplied_via_save_method(self): obj = self.obj @@ -149,6 +154,11 @@ class SimpleModelTest(TestCase): "when using the `update_fields`." ), ) + self.assertEqual( + obj.history.get(action=LogEntry.Action.UPDATE).changes_str, + "boolean: False → True", + msg="Changes string is correct", + ) def test_django_update_fields_edge_cases(self): """ @@ -179,6 +189,11 @@ class SimpleModelTest(TestCase): {"boolean": ["False", "True"], "integer": ["None", "1"]}, msg="The 2 fields changed are correctly logged", ) + self.assertEqual( + obj.history.get(action=LogEntry.Action.UPDATE).changes_str, + "boolean: False → True; integer: None → 1", + msg="Changes string is correct", + ) def test_delete(self): """Deletion is logged correctly.""" @@ -732,6 +747,11 @@ class SimpleIncludeModelTest(TestCase): {"label": ["Initial label", "New label"]}, msg="Only the label was logged, regardless of multiple entries in `update_fields`", ) + self.assertEqual( + obj.history.get(action=LogEntry.Action.UPDATE).changes_str, + "label: Initial label → New label", + msg="Changes string is correct", + ) def test_register_include_fields(self): sim = SimpleIncludeModel(label="Include model", text="Looong text") @@ -2068,6 +2088,11 @@ class JSONModelTest(TestCase): {"json": ["{}", '{"quantity": "1"}']}, msg="The change is correctly logged", ) + self.assertEqual( + history.changes_str, + "json: {} → {\"quantity\": \"1\"}", + msg="Changes string is correct", + ) def test_update_with_no_changes(self): """No changes are logged.""" @@ -2704,6 +2729,7 @@ class TestAccessLog(TestCase): ) self.assertIsNone(log_entry.changes) self.assertEqual(log_entry.changes_dict, {}) + self.assertEqual(log_entry.changes_str, "") class SignalTests(TestCase): @@ -3127,6 +3153,7 @@ class BaseManagerSettingTest(TestCase): } }, ) + self.assertEqual(log_entry.changes_str, f"m2m_related: add {[smart_str(obj_two)]}") class TestMaskStr(TestCase):