diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a4651c..968edb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ #### Fixes +- fix: Audit changes to FK fields when saved using `*_id` naming. ([#525](https://github.com/jazzband/django-auditlog/pull/525)) - fix: Fix a bug in audit log admin page when `USE_TZ=False`. ([#511](https://github.com/jazzband/django-auditlog/pull/511)) - fix: Make sure `LogEntry.changes_dict()` returns an empty dict instead of `None` when `json.loads()` returns `None`. ([#472](https://github.com/jazzband/django-auditlog/pull/472)) - fix: Always set remote_addr even if the request has no authenticated user. ([#484](https://github.com/jazzband/django-auditlog/pull/484)) diff --git a/auditlog/diff.py b/auditlog/diff.py index 94a910f..eece725 100644 --- a/auditlog/diff.py +++ b/auditlog/diff.py @@ -4,7 +4,7 @@ from typing import Optional from django.conf import settings from django.core.exceptions import ObjectDoesNotExist -from django.db.models import NOT_PROVIDED, DateTimeField, JSONField, Model +from django.db.models import NOT_PROVIDED, DateTimeField, ForeignKey, JSONField, Model from django.utils import timezone as django_timezone from django.utils.encoding import smart_str @@ -147,7 +147,14 @@ def model_instance_diff( model_fields = None if fields_to_check: - fields = {field for field in fields if field.name in fields_to_check} + fields = { + field + for field in fields + if ( + (isinstance(field, ForeignKey) and field.attname in fields_to_check) + or (field.name in fields_to_check) + ) + } # Check if fields must be filtered if ( diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index 09aad02..223ad99 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -1858,6 +1858,32 @@ class TestRelatedDiffs(TestCase): self.assertEqual(int(log_one.changes_dict["one_to_one"][1]), simple.id) self.assertEqual(int(log_two.changes_dict["related"][1]), two_simple.id) + def test_log_entry_changes_on_fk_object_id_update(self): + t1 = self.test_date + with freezegun.freeze_time(t1): + simple = SimpleModel.objects.create() + one_simple = SimpleModel.objects.create() + two_simple = SimpleModel.objects.create() + instance = RelatedModel.objects.create( + one_to_one=simple, related=one_simple + ) + + t2 = self.test_date + datetime.timedelta(days=20) + with freezegun.freeze_time(t2): + instance.related_id = two_simple.id + instance.one_to_one = one_simple + instance.save(update_fields=["related_id", "one_to_one_id"]) + + log_one = instance.history.filter(timestamp=t1).first() + log_two = instance.history.filter(timestamp=t2).first() + self.assertTrue(isinstance(log_one, LogEntry)) + self.assertTrue(isinstance(log_two, LogEntry)) + + self.assertEqual(int(log_one.changes_dict["related"][1]), one_simple.id) + self.assertEqual(int(log_one.changes_dict["one_to_one"][1]), simple.id) + self.assertEqual(int(log_two.changes_dict["related"][1]), two_simple.id) + self.assertEqual(int(log_two.changes_dict["one_to_one"][1]), one_simple.id) + def test_log_entry_changes_on_fk_id_update(self): t1 = self.test_date with freezegun.freeze_time(t1):