diff --git a/wagtail/admin/views/pages/listing.py b/wagtail/admin/views/pages/listing.py index 5a7609d438..be375f74e8 100644 --- a/wagtail/admin/views/pages/listing.py +++ b/wagtail/admin/views/pages/listing.py @@ -185,6 +185,10 @@ class IndexView(generic.IndexView): return super().get(request) + @cached_property + def i18n_enabled(self): + return getattr(settings, "WAGTAIL_I18N_ENABLED", False) + def get_valid_orderings(self): valid_orderings = super().get_valid_orderings() @@ -230,6 +234,8 @@ class IndexView(generic.IndexView): # Annotate queryset with various states to be used later for performance optimisations if getattr(settings, "WAGTAIL_WORKFLOW_ENABLED", True): pages = pages.prefetch_workflow_states() + if self.i18n_enabled: + pages = pages.annotate_has_untranslated_locale() pages = pages.annotate_site_root_state().annotate_approved_schedule() @@ -351,7 +357,6 @@ class ExplorableIndexView(IndexView): self.parent_page = self.parent_page.specific self.scheduled_page = self.parent_page.get_scheduled_revision_as_object() - self.i18n_enabled = getattr(settings, "WAGTAIL_I18N_ENABLED", False) if self.i18n_enabled and not self.parent_page.is_root(): self.locale = self.parent_page.locale self.translations = self.get_translations() diff --git a/wagtail/contrib/simple_translation/tests/test_views.py b/wagtail/contrib/simple_translation/tests/test_views.py index a002ec28c2..d495881cff 100644 --- a/wagtail/contrib/simple_translation/tests/test_views.py +++ b/wagtail/contrib/simple_translation/tests/test_views.py @@ -476,7 +476,7 @@ class TestPageListing(WagtailTestUtils, TestCase): def test_translate_button_displayed(self): url = reverse("wagtailadmin_explore", args=(self.en_homepage.pk,)) response = self.client.get(url) - with self.assertNumQueries(50): + with self.assertNumQueries(40): response = self.client.get(url) soup = self.get_soup(response.content) diff --git a/wagtail/contrib/simple_translation/wagtail_hooks.py b/wagtail/contrib/simple_translation/wagtail_hooks.py index f44340af97..019bb471c8 100644 --- a/wagtail/contrib/simple_translation/wagtail_hooks.py +++ b/wagtail/contrib/simple_translation/wagtail_hooks.py @@ -48,13 +48,18 @@ def register_submit_translation_permission(): @hooks.register("register_page_listing_more_buttons") def page_listing_more_buttons(page, user, next_url=None): if user.has_perm("simple_translation.submit_translation") and not page.is_root(): - # If there's at least one locale that we haven't translated into yet, - # show "Translate this page" button - has_locale_to_translate_to = Locale.objects.exclude( - id__in=page.get_translations(inclusive=True).values_list( - "locale_id", flat=True - ) - ).exists() + if hasattr(page, "_has_untranslated_locale"): + # `_has_untranslated_locale` may be populated by `annotate_has_untranslated_locale` + # on querysets as a performance optimisation + has_locale_to_translate_to = page._has_untranslated_locale + else: + # If there's at least one locale that we haven't translated into yet, + # show "Translate this page" button + has_locale_to_translate_to = Locale.objects.exclude( + id__in=page.get_translations(inclusive=True).values_list( + "locale_id", flat=True + ) + ).exists() if has_locale_to_translate_to: url = reverse("simple_translation:submit_page_translation", args=[page.id]) diff --git a/wagtail/query.py b/wagtail/query.py index 95c776b979..a1ff2b97f5 100644 --- a/wagtail/query.py +++ b/wagtail/query.py @@ -12,6 +12,7 @@ from django.db.models.functions import Cast, Length, Substr from django.db.models.query import BaseIterable, ModelIterable from treebeard.mp_tree import MP_NodeQuerySet +from wagtail.models.i18n import Locale from wagtail.models.sites import Site from wagtail.search.queryset import SearchableQuerySetMixin @@ -508,6 +509,17 @@ class PageQuerySet(SearchableQuerySetMixin, SpecificQuerySetMixin, TreeQuerySet) ) ) + def annotate_has_untranslated_locale(self): + return self.annotate( + _has_untranslated_locale=Exists( + Locale.objects.exclude( + id__in=self.model.objects.filter( + translation_key=OuterRef(OuterRef("translation_key")) + ).values("locale_id") + ) + ) + ) + class SpecificIterable(BaseIterable): def __iter__(self):