diff --git a/auditlog/conf.py b/auditlog/conf.py index 9046669a..c7f93f5b 100644 --- a/auditlog/conf.py +++ b/auditlog/conf.py @@ -40,3 +40,6 @@ settings.AUDITLOG_USE_TEXT_CHANGES_IF_JSON_IS_NOT_PRESENT = getattr( settings, "AUDITLOG_USE_TEXT_CHANGES_IF_JSON_IS_NOT_PRESENT", False ) + +# Custom +settings.AUDITLOG_DISABLE_AUDITLOG = getattr(settings, "AUDITLOG", {}).get("disable_auditlog", False) diff --git a/auditlog/migrations/0010_alter_logentry_timestamp.py b/auditlog/migrations/0010_alter_logentry_timestamp.py index d18bf484..ad560a2c 100644 --- a/auditlog/migrations/0010_alter_logentry_timestamp.py +++ b/auditlog/migrations/0010_alter_logentry_timestamp.py @@ -9,11 +9,25 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AlterField( - model_name="logentry", - name="timestamp", - field=models.DateTimeField( - auto_now_add=True, db_index=True, verbose_name="timestamp" - ), + migrations.SeparateDatabaseAndState( + database_operations=[ + migrations.RunSQL( + sql=""" + CREATE INDEX "auditlog_logentry_v2_timestamp_37867bb0" ON "auditlog_logentry" ("timestamp"); + """, + reverse_sql=""" + DROP INDEX CONCURRENTLY IF EXISTS "auditlog_logentry_v2_timestamp_37867bb0"; + """ + ), + ], + state_operations=[ + migrations.AlterField( + model_name="logentry", + name="timestamp", + field=models.DateTimeField( + auto_now_add=True, db_index=True, verbose_name="timestamp" + ), + ), + ], ), ] diff --git a/auditlog/receivers.py b/auditlog/receivers.py index a0675808..67c8042a 100644 --- a/auditlog/receivers.py +++ b/auditlog/receivers.py @@ -152,11 +152,17 @@ def make_log_m2m_changes(field_name): @check_disable def log_m2m_changes(signal, action, **kwargs): """Handle m2m_changed and call LogEntry.objects.log_m2m_changes as needed.""" - if action not in ["post_add", "post_clear", "post_remove"]: + if action not in ["post_add", "pre_clear", "post_remove"]: return - if action == "post_clear": - changed_queryset = kwargs["model"].objects.all() + if action == "pre_clear": + # UPDATE: This is making the log for all existing rows in the M2M model, + # resulting to low performance. Instead we will, + # 1. Catch pre-clear signal + # 2. Record M2M associated rows before clearing + # See known issue: https://github.com/jazzband/django-auditlog/issues/539 + # changed_queryset = kwargs["model"].objects.all() + changed_queryset = getattr(kwargs["instance"], field_name).all() else: changed_queryset = kwargs["model"].objects.filter(pk__in=kwargs["pk_set"]) @@ -167,7 +173,7 @@ def log_m2m_changes(signal, action, **kwargs): "add", field_name, ) - elif action in ["post_remove", "post_clear"]: + elif action in ["post_remove", "pre_clear"]: LogEntry.objects.log_m2m_changes( changed_queryset, kwargs["instance"], diff --git a/auditlog/registry.py b/auditlog/registry.py index 3f1f8f30..7f9a918d 100644 --- a/auditlog/registry.py +++ b/auditlog/registry.py @@ -55,6 +55,9 @@ def __init__( self._signals = {} self._m2m_signals = defaultdict(dict) + if settings.AUDITLOG_DISABLE_AUDITLOG: + return + if create: self._signals[post_save] = log_create if update: @@ -195,6 +198,9 @@ def _connect_signals(self, model): """ from auditlog.receivers import make_log_m2m_changes + if settings.AUDITLOG_DISABLE_AUDITLOG: + return + for signal, receiver in self._signals.items(): signal.connect( receiver,