|
@@ -1,10 +1,20 @@
|
|
|
import logging
|
|
|
+from contextlib import contextmanager
|
|
|
|
|
|
+from asgiref.local import Local
|
|
|
from django.core.cache import cache
|
|
|
-from django.db.models.signals import post_delete, post_save, pre_delete
|
|
|
+from django.db import transaction
|
|
|
+from django.db.models.signals import (
|
|
|
+ post_delete,
|
|
|
+ post_migrate,
|
|
|
+ post_save,
|
|
|
+ pre_delete,
|
|
|
+ pre_migrate,
|
|
|
+)
|
|
|
+from modelcluster.fields import ParentalKey
|
|
|
|
|
|
from wagtail.coreutils import get_locales_display_names
|
|
|
-from wagtail.models import Locale, Page, Site
|
|
|
+from wagtail.models import Locale, Page, ReferenceIndex, Site
|
|
|
|
|
|
logger = logging.getLogger("wagtail")
|
|
|
|
|
@@ -33,6 +43,70 @@ def reset_locales_display_names_cache(sender, instance, **kwargs):
|
|
|
get_locales_display_names.cache_clear()
|
|
|
|
|
|
|
|
|
+reference_index_auto_update_disabled = Local()
|
|
|
+
|
|
|
+
|
|
|
+@contextmanager
|
|
|
+def disable_reference_index_auto_update():
|
|
|
+ """
|
|
|
+ A context manager that can be used to temporarily disable the reference index auto-update signal handlers.
|
|
|
+
|
|
|
+ For example:
|
|
|
+
|
|
|
+ with disable_reference_index_auto_update():
|
|
|
+ my_instance.save() # Reference index will not be updated by this save
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ reference_index_auto_update_disabled.value = True
|
|
|
+ yield
|
|
|
+ finally:
|
|
|
+ del reference_index_auto_update_disabled.value
|
|
|
+
|
|
|
+
|
|
|
+def update_reference_index_on_save(instance, **kwargs):
|
|
|
+ # Don't populate reference index while loading fixtures as referenced objects may not be populated yet
|
|
|
+ if kwargs.get("raw", False):
|
|
|
+ return
|
|
|
+
|
|
|
+ if getattr(reference_index_auto_update_disabled, "value", False):
|
|
|
+ return
|
|
|
+
|
|
|
+ # If the model is a child model, find the parent instance and index that instead
|
|
|
+ while True:
|
|
|
+ parental_keys = list(
|
|
|
+ filter(
|
|
|
+ lambda field: isinstance(field, ParentalKey),
|
|
|
+ instance._meta.get_fields(),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ if not parental_keys:
|
|
|
+ break
|
|
|
+
|
|
|
+ instance = getattr(instance, parental_keys[0].name)
|
|
|
+
|
|
|
+ if ReferenceIndex.model_is_indexible(type(instance)):
|
|
|
+ with transaction.atomic():
|
|
|
+ ReferenceIndex.create_or_update_for_object(instance)
|
|
|
+
|
|
|
+
|
|
|
+def remove_reference_index_on_delete(instance, **kwargs):
|
|
|
+ if getattr(reference_index_auto_update_disabled, "value", False):
|
|
|
+ return
|
|
|
+
|
|
|
+ with transaction.atomic():
|
|
|
+ ReferenceIndex.remove_for_object(instance)
|
|
|
+
|
|
|
+
|
|
|
+def connect_reference_index_signal_handlers(**kwargs):
|
|
|
+ post_save.connect(update_reference_index_on_save)
|
|
|
+ post_delete.connect(remove_reference_index_on_delete)
|
|
|
+
|
|
|
+
|
|
|
+def disconnect_reference_index_signal_handlers(**kwargs):
|
|
|
+ post_save.disconnect(update_reference_index_on_save)
|
|
|
+ post_delete.disconnect(remove_reference_index_on_delete)
|
|
|
+
|
|
|
+
|
|
|
def register_signal_handlers():
|
|
|
post_save.connect(post_save_site_signal_handler, sender=Site)
|
|
|
post_delete.connect(post_delete_site_signal_handler, sender=Site)
|
|
@@ -42,3 +116,11 @@ def register_signal_handlers():
|
|
|
|
|
|
post_save.connect(reset_locales_display_names_cache, sender=Locale)
|
|
|
post_delete.connect(reset_locales_display_names_cache, sender=Locale)
|
|
|
+
|
|
|
+ # Reference index signal handlers
|
|
|
+ connect_reference_index_signal_handlers()
|
|
|
+
|
|
|
+ # Disconnect reference index signals while migrations are running
|
|
|
+ # (we don't want to log references in migrations as the ReferenceIndex model might not exist)
|
|
|
+ pre_migrate.connect(disconnect_reference_index_signal_handlers)
|
|
|
+ post_migrate.connect(connect_reference_index_signal_handlers)
|