From 06ae048378fece0226c3ad156a53f20c8bc7ff00 Mon Sep 17 00:00:00 2001 From: "Aaron C. de Bruyn" Date: Fri, 20 Jan 2023 06:41:36 -0800 Subject: [PATCH] Add ability to globally exclude fields by name on all models (#498) Co-authored-by: Hasan Ramezani --- CHANGELOG.md | 1 + auditlog/conf.py | 5 +++++ auditlog/registry.py | 17 +++++++++++++++++ auditlog_tests/tests.py | 38 ++++++++++++++++++++++++++++++++++++++ docs/source/usage.rst | 17 +++++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fbce33..2108aca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - 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)) - feat: Make timestamp in LogEntry overwritable. ([#476](https://github.com/jazzband/django-auditlog/pull/476)) +- feat: Support excluding field names globally when ```AUDITLOG_INCLUDE_ALL_MODELS``` is enabled. ([#498](https://github.com/jazzband/django-auditlog/pull/498)) #### Fixes diff --git a/auditlog/conf.py b/auditlog/conf.py index a56a165..2050677 100644 --- a/auditlog/conf.py +++ b/auditlog/conf.py @@ -16,6 +16,11 @@ settings.AUDITLOG_INCLUDE_TRACKING_MODELS = getattr( settings, "AUDITLOG_INCLUDE_TRACKING_MODELS", () ) +# Exclude named fields across all models +settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS = getattr( + settings, "AUDITLOG_EXCLUDE_TRACKING_FIELDS", () +) + # Disable on raw save to avoid logging imports and similar settings.AUDITLOG_DISABLE_ON_RAW_SAVE = getattr( settings, "AUDITLOG_DISABLE_ON_RAW_SAVE", False diff --git a/auditlog/registry.py b/auditlog/registry.py index 998105f..3bb9a64 100644 --- a/auditlog/registry.py +++ b/auditlog/registry.py @@ -113,6 +113,9 @@ class AuditlogModelRegistry: "set. Did you forget to set serialized_data to True?" ) + for fld in settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS: + exclude_fields.append(fld) + def registrar(cls): """Register models for a given class.""" if not issubclass(cls, Model): @@ -293,11 +296,25 @@ class AuditlogModelRegistry: "setting 'AUDITLOG_INCLUDE_ALL_MODELS' must set to 'True'" ) + if ( + settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS + and not settings.AUDITLOG_INCLUDE_ALL_MODELS + ): + raise ValueError( + "In order to use 'AUDITLOG_EXCLUDE_TRACKING_FIELDS', " + "setting 'AUDITLOG_INCLUDE_ALL_MODELS' must be set to 'True'" + ) + if not isinstance(settings.AUDITLOG_INCLUDE_TRACKING_MODELS, (list, tuple)): raise TypeError( "Setting 'AUDITLOG_INCLUDE_TRACKING_MODELS' must be a list or tuple" ) + if not isinstance(settings.AUDITLOG_EXCLUDE_TRACKING_FIELDS, (list, tuple)): + raise TypeError( + "Setting 'AUDITLOG_EXCLUDE_TRACKING_FIELDS' must be a list or tuple" + ) + for item in settings.AUDITLOG_INCLUDE_TRACKING_MODELS: if not isinstance(item, (str, dict)): raise TypeError( diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index 5b43f50..487a45d 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -1159,6 +1159,26 @@ class RegisterModelSettingsTest(TestCase): ): self.test_auditlog.register_from_settings() + with override_settings( + AUDITLOG_INCLUDE_ALL_MODELS=True, + AUDITLOG_EXCLUDE_TRACKING_FIELDS="badvalue", + ): + with self.assertRaisesMessage( + TypeError, + "Setting 'AUDITLOG_EXCLUDE_TRACKING_FIELDS' must be a list or tuple", + ): + self.test_auditlog.register_from_settings() + + with override_settings( + AUDITLOG_EXCLUDE_TRACKING_FIELDS=("created", "modified") + ): + with self.assertRaisesMessage( + ValueError, + "In order to use 'AUDITLOG_EXCLUDE_TRACKING_FIELDS', " + "setting 'AUDITLOG_INCLUDE_ALL_MODELS' must be set to 'True'", + ): + self.test_auditlog.register_from_settings() + with override_settings(AUDITLOG_INCLUDE_TRACKING_MODELS="str"): with self.assertRaisesMessage( TypeError, @@ -1218,6 +1238,24 @@ class RegisterModelSettingsTest(TestCase): self.assertFalse(self.test_auditlog.contains(SimpleExcludeModel)) self.assertTrue(self.test_auditlog.contains(ChoicesFieldModel)) + @override_settings( + AUDITLOG_INCLUDE_ALL_MODELS=True, + AUDITLOG_EXCLUDE_TRACKING_FIELDS=("datetime",), + ) + def test_register_from_settings_register_all_models_with_exclude_tracking_fields( + self, + ): + self.test_auditlog.register_from_settings() + + self.assertEqual( + self.test_auditlog.get_model_fields(SimpleModel)["exclude_fields"], + ["datetime"], + ) + self.assertEqual( + self.test_auditlog.get_model_fields(AltPrimaryKeyModel)["exclude_fields"], + ["datetime"], + ) + @override_settings( AUDITLOG_INCLUDE_ALL_MODELS=True, AUDITLOG_EXCLUDE_TRACKING_MODELS=["auditlog_tests.SimpleExcludeModel"], diff --git a/docs/source/usage.rst b/docs/source/usage.rst index 4961be2..376737a 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -189,6 +189,23 @@ You can use this setting to register all your models: .. versionadded:: 2.1.0 +**AUDITLOG_EXCLUDE_TRACKING_FIELDS** + +You can use this setting to exclude named fields from ALL models. +This is useful when lots of models share similar fields like +```created``` and ```modified``` and you want those excluded from +logging. +It will be considered when ``AUDITLOG_INCLUDE_ALL_MODELS`` is `True`. + +.. code-block:: python + + AUDITLOG_EXCLUDE_TRACKING_FIELDS = ( + "created", + "modified" + ) + +.. versionadded:: 3.0.0 + **AUDITLOG_EXCLUDE_TRACKING_MODELS** You can use this setting to exclude models in registration process.