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