diff --git a/CHANGELOG.md b/CHANGELOG.md index 6576baf..4810340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ #### Improvements +- Changes the view when it has changes in fields `JSONField`. The `JSONField.encoder` is assigned to `json.dumps`. ([#489](https://github.com/jazzband/django-auditlog/pull/489)) - feat: Added support for Correlation ID. ([#481](https://github.com/jazzband/django-auditlog/pull/481)) - feat: Added pre-log and post-log signals. ([#483](https://github.com/jazzband/django-auditlog/pull/483)) diff --git a/auditlog/diff.py b/auditlog/diff.py index cf62504..94a910f 100644 --- a/auditlog/diff.py +++ b/auditlog/diff.py @@ -1,3 +1,4 @@ +import json from datetime import timezone from typing import Optional @@ -74,6 +75,7 @@ def get_field_value(obj, field): value = django_timezone.make_naive(value, timezone=timezone.utc) elif isinstance(field, JSONField): value = field.to_python(getattr(obj, field.name, None)) + value = json.dumps(value, sort_keys=True, cls=field.encoder) elif (field.one_to_one or field.many_to_one) and hasattr(field, "rel_class"): value = smart_str( getattr(obj, field.get_attname(), None), strings_only=True diff --git a/auditlog_tests/models.py b/auditlog_tests/models.py index 10a5503..6b69eec 100644 --- a/auditlog_tests/models.py +++ b/auditlog_tests/models.py @@ -1,6 +1,7 @@ import uuid from django.contrib.postgres.fields import ArrayField +from django.core.serializers.json import DjangoJSONEncoder from django.db import models from auditlog.models import AuditlogHistoryField @@ -260,7 +261,7 @@ class NoDeleteHistoryModel(models.Model): class JSONModel(models.Model): - json = models.JSONField(default=dict) + json = models.JSONField(default=dict, encoder=DjangoJSONEncoder) history = AuditlogHistoryField(delete_related=False) diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index cf8f0df..feb5490 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -1601,7 +1601,7 @@ class JSONModelTest(TestCase): self.assertDictEqual( history.changes, - {"json": ["{}", "{'quantity': '1'}"]}, + {"json": ["{}", '{"quantity": "1"}']}, msg="The change is correctly logged", ) @@ -1693,6 +1693,34 @@ class ModelInstanceDiffTest(TestCase): msg="ObjectDoesNotExist should be handled", ) + def test_diff_models_with_json_fields(self): + first = JSONModel.objects.create( + json={ + "code": "17", + "date": datetime.date(2022, 1, 1), + "description": "first", + } + ) + first.refresh_from_db() # refresh json data from db + second = JSONModel.objects.create( + json={ + "code": "17", + "description": "second", + "date": datetime.date(2023, 1, 1), + } + ) + diff = model_instance_diff(first, second, ["json"]) + + self.assertDictEqual( + diff, + { + "json": ( + '{"code": "17", "date": "2022-01-01", "description": "first"}', + '{"code": "17", "date": "2023-01-01", "description": "second"}', + ) + }, + ) + class TestRelatedDiffs(TestCase): def setUp(self):