From 12d34e2cb1b0e905d3a4be781e88e431f064d848 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Thu, 15 Oct 2026 01:03:41 +0200 Subject: [PATCH] dnscms: prefetch images and related objects that GraphQL listings resolve per item --- dnscms/associations/models.py | 4 +++- dnscms/contacts/models.py | 8 ++++++++ dnscms/dnscms/wagtail_hooks.py | 7 ++++++- dnscms/events/models.py | 20 +++++++++++++++++--- dnscms/news/models.py | 4 +++- dnscms/venues/models.py | 4 +++- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/dnscms/associations/models.py b/dnscms/associations/models.py index f735147..e9ceb6c 100644 --- a/dnscms/associations/models.py +++ b/dnscms/associations/models.py @@ -18,7 +18,9 @@ from dnscms.wordpress.models import DeferWPFieldsManagerMixin, WPImportedPageMix class AssociationPageManager(DeferWPFieldsManagerMixin, PageManager): - pass + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("logo") @register_singular_query_field("associationIndex") diff --git a/dnscms/contacts/models.py b/dnscms/contacts/models.py index 7f834a2..cf3408d 100644 --- a/dnscms/contacts/models.py +++ b/dnscms/contacts/models.py @@ -42,6 +42,12 @@ class ContactIndex(HeadlessMixin, Page): search_fields = Page.search_fields + [index.SearchField("body")] +class ContactEntityManager(models.Manager): + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("image") + + @register_snippet @register_query_field("contactEntity", "contactEntities") class ContactEntity(models.Model): @@ -73,6 +79,8 @@ class ContactEntity(models.Model): related_name="+", ) + objects = ContactEntityManager() + title_widget = forms.TextInput(attrs={"placeholder": "Navn*"}) panels = [ diff --git a/dnscms/dnscms/wagtail_hooks.py b/dnscms/dnscms/wagtail_hooks.py index 21e8529..7a59dae 100644 --- a/dnscms/dnscms/wagtail_hooks.py +++ b/dnscms/dnscms/wagtail_hooks.py @@ -1,5 +1,6 @@ import graphene +from django.db.models import prefetch_related_objects from django.templatetags.static import static from django.utils.html import format_html from grapple.registry import registry as grapple_registry @@ -10,6 +11,7 @@ from wagtail.models import Page from wagtail.search.backends import get_search_backend from dnscms.rich_text import register_button_link_feature +from events.models import EventPage @hooks.register("register_rich_text_features") @@ -65,7 +67,10 @@ def override_search_field(query_mixins): return [] ids = [p.id for p in ranked] specific_map = {p.id: p for p in Page.objects.filter(id__in=ids).specific()} - return [specific_map[i] for i in ids if i in specific_map] + results = [specific_map[i] for i in ids if i in specific_map] + events = [p for p in results if isinstance(p, EventPage)] + prefetch_related_objects(events, "occurrences") + return results query_mixins.insert(0, SearchOverrideMixin) diff --git a/dnscms/events/models.py b/dnscms/events/models.py index dceb693..c15dee8 100644 --- a/dnscms/events/models.py +++ b/dnscms/events/models.py @@ -164,10 +164,16 @@ class EventOrganizerLink(Orderable): ] +class EventOrganizerManager(WPAwareManager): + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("association") + + # registered as a snippet via EventOrganizerSnippetViewSet in wagtail_hooks.py @register_query_field("eventOrganizer", "eventOrganizers") class EventOrganizer(index.Indexed, ClusterableModel): - objects = WPAwareManager() + objects = EventOrganizerManager() name = models.CharField( max_length=100, @@ -250,7 +256,9 @@ class EventPageManager( DeferWPFieldsManagerMixin, PageManager.from_queryset(EventPageQuerySet), ): - pass + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("featured_image") class EventPage(HeadlessMixin, WPImportedPageMixin, Page): @@ -450,8 +458,14 @@ class EventPage(HeadlessMixin, WPImportedPageMixin, Page): self.price_member = "" +class EventOccurrenceManager(WPAwareManager): + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("venue") + + class EventOccurrence(Orderable): - objects = WPAwareManager() + objects = EventOccurrenceManager() event = ParentalKey(EventPage, on_delete=models.CASCADE, related_name="occurrences") start = models.DateTimeField() diff --git a/dnscms/news/models.py b/dnscms/news/models.py index 2f0ccbe..d9de61d 100644 --- a/dnscms/news/models.py +++ b/dnscms/news/models.py @@ -13,7 +13,9 @@ from dnscms.wordpress.models import DeferWPFieldsManagerMixin, WPImportedPageMix class NewsPageManager(DeferWPFieldsManagerMixin, PageManager): - pass + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("featured_image") @register_singular_query_field("newsIndex") diff --git a/dnscms/venues/models.py b/dnscms/venues/models.py index 939819d..443a12f 100644 --- a/dnscms/venues/models.py +++ b/dnscms/venues/models.py @@ -20,7 +20,9 @@ from dnscms.wordpress.models import DeferWPFieldsManagerMixin, WPImportedPageMix class VenuePageManager(DeferWPFieldsManagerMixin, PageManager): - pass + def get_queryset(self): + # GraphQL lists load these through here; saves a query per item + return super().get_queryset().prefetch_related("featured_image") @register_singular_query_field("venueIndex")