From ee278edc8f2cc998f24aa12fede88a4c9479a9a5 Mon Sep 17 00:00:00 2001 From: peyman Date: Thu, 9 Oct 2025 14:11:21 +0330 Subject: [PATCH 1/2] Add option to exclude reverse relations from model diffs Add AUDITLOG_EXCLUDE_REVERSE_RELATIONS setting which, when True, excludes auto-created reverse relation fields (auto_created and not concrete) from the diff calculation to avoid extra DB hits and inadvertent mutation of instance._state.fields_cache. Closes #551 (or: Fixes behavior described in jazzband/django-auditlog#551). --- auditlog/conf.py | 5 +++++ auditlog/diff.py | 10 ++++++++++ docs/source/usage.rst | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/auditlog/conf.py b/auditlog/conf.py index b151b24..254ecd0 100644 --- a/auditlog/conf.py +++ b/auditlog/conf.py @@ -21,6 +21,11 @@ settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS = getattr( settings, "AUDITLOG_EXCLUDE_TRACKING_FIELDS", () ) +# Exclude reverse relation fields across all models +settings.AUDITLOG_EXCLUDE_REVERSE_RELATIONS = getattr( + settings, "AUDITLOG_EXCLUDE_REVERSE_RELATIONS", False +) + # Mask named fields across all models settings.AUDITLOG_MASK_TRACKING_FIELDS = getattr( settings, "AUDITLOG_MASK_TRACKING_FIELDS", () diff --git a/auditlog/diff.py b/auditlog/diff.py index fc98987..a45c38c 100644 --- a/auditlog/diff.py +++ b/auditlog/diff.py @@ -213,6 +213,16 @@ def model_instance_diff( fields = set() model_fields = None + # Optionally exclude reverse relations (auto-created fields). + # Reverse relations (auto_created & not concrete) can cause unwanted DB hits + # and mutate instance._state.fields_cache as a side-effect. + # Make this behavior opt-in via AUDITLOG_EXCLUDE_REVERSE_RELATIONS. + if settings.AUDITLOG_EXCLUDE_REVERSE_RELATIONS: + def is_reverse_field(f): + return getattr(f, "auto_created", False) and not getattr(f, "concrete", False) + + fields = {f for f in fields if not is_reverse_field(f)} + if fields_to_check: fields = { field diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 4f9dda6..148a4ac 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -574,3 +574,13 @@ The mixin provides the following configuration options: - ``auditlog_history_template``: Template to use for rendering the history page (default: ``auditlog/object_history.html``) - ``auditlog_history_per_page``: Number of log entries to display per page (default: 10) +.. versionadded:: 3.2.2 + +Default: False + +Use ``AUDITLOG_EXCLUDE_REVERSE_RELATIONS`` to exclude reverse relation fields (auto-created fields +where `field.auto_created is True` and `field.concrete is False`) when computing +model diffs. This avoids accidental database queries for related objects and avoids +mutating `instance._state.fields_cache` as a side-effect. + +Added to address: https://github.com/jazzband/django-auditlog/issues/551 From 952924f4cf0c9303faa3cf7955737a9f56db45aa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 10:45:55 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- auditlog/diff.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/auditlog/diff.py b/auditlog/diff.py index a45c38c..a69465c 100644 --- a/auditlog/diff.py +++ b/auditlog/diff.py @@ -218,8 +218,11 @@ def model_instance_diff( # and mutate instance._state.fields_cache as a side-effect. # Make this behavior opt-in via AUDITLOG_EXCLUDE_REVERSE_RELATIONS. if settings.AUDITLOG_EXCLUDE_REVERSE_RELATIONS: + def is_reverse_field(f): - return getattr(f, "auto_created", False) and not getattr(f, "concrete", False) + return getattr(f, "auto_created", False) and not getattr( + f, "concrete", False + ) fields = {f for f in fields if not is_reverse_field(f)}