Add method to prefetch for listing

This commit is contained in:
Jake Howard 2022-08-28 14:52:27 +01:00
parent 735ab73ec0
commit c660e54bae
Signed by: jake
GPG Key ID: 57AFB45680EDD477
4 changed files with 29 additions and 23 deletions

View File

@ -8,7 +8,7 @@ from modelcluster.fields import ParentalManyToManyField
from wagtail.admin.panels import FieldPanel from wagtail.admin.panels import FieldPanel
from website.common.models import BaseContentPage, BaseListingPage from website.common.models import BaseContentPage, BaseListingPage
from website.common.utils import TocEntry from website.common.utils import TocEntry, prefetch_for_listing
from website.common.views import ContentPageFeed from website.common.views import ContentPageFeed
@ -37,12 +37,8 @@ class BlogPostListPage(BaseListingPage):
return [TocEntry(post_month, post_month, 0, []) for post_month in post_months] return [TocEntry(post_month, post_month, 0, []) for post_month in post_months]
def get_listing_pages(self) -> models.QuerySet: def get_listing_pages(self) -> models.QuerySet:
return ( return prefetch_for_listing(
BlogPostPage.objects.descendant_of(self) BlogPostPage.objects.descendant_of(self).live().order_by("-date", "title").prefetch_related("tags")
.live()
.select_related("hero_image", "hero_unsplash_photo")
.prefetch_related("tags")
.order_by("-date", "title")
) )
@property @property
@ -117,9 +113,8 @@ class BlogPostCollectionPage(BaseListingPage):
subpage_types = [BlogPostPage] subpage_types = [BlogPostPage]
def get_listing_pages(self) -> models.QuerySet: def get_listing_pages(self) -> models.QuerySet:
return ( return prefetch_for_listing(
BlogPostPage.objects.child_of(self) BlogPostPage.objects.child_of(self).live()
.select_related("hero_image", "hero_unsplash_photo")
.prefetch_related("tags") .prefetch_related("tags")
.order_by("-date", "title") .order_by("-date", "title")
) )

View File

@ -22,12 +22,18 @@ from wagtail.search import index
from wagtail.snippets.models import register_snippet from wagtail.snippets.models import register_snippet
from wagtailmetadata.models import MetadataMixin from wagtailmetadata.models import MetadataMixin
from website.common.utils import count_words
from website.contrib.unsplash.widgets import UnsplashPhotoChooser from website.contrib.unsplash.widgets import UnsplashPhotoChooser
from .serializers import PaginationSerializer from .serializers import PaginationSerializer
from .streamfield import add_heading_anchors, get_blocks, get_content_html from .streamfield import add_heading_anchors, get_blocks, get_content_html
from .utils import TocEntry, extract_text, get_table_of_contents, truncate_string from .utils import (
TocEntry,
count_words,
extract_text,
get_table_of_contents,
prefetch_for_listing,
truncate_string,
)
class BasePage(Page): class BasePage(Page):
@ -196,12 +202,8 @@ class BaseListingPage(RoutablePageMixin, BaseContentPage):
abstract = True abstract = True
def get_listing_pages(self) -> models.QuerySet: def get_listing_pages(self) -> models.QuerySet:
return ( return prefetch_for_listing(
self.get_children() self.get_children().live().specific().order_by("title")
.live()
.specific()
.select_related("hero_image", "hero_unsplash_photo")
.order_by("title")
) )
def get_paginator_page(self) -> PaginatorPage: def get_paginator_page(self) -> PaginatorPage:

View File

@ -9,6 +9,7 @@ from django.utils.text import slugify, smart_split
from more_itertools import ilen from more_itertools import ilen
from wagtail.models import Page from wagtail.models import Page
from wagtail.models import get_page_models as get_wagtail_page_models from wagtail.models import get_page_models as get_wagtail_page_models
from wagtail.query import PageQuerySet
HEADER_TAGS = ["h2", "h3", "h4", "h5", "h6"] HEADER_TAGS = ["h2", "h3", "h4", "h5", "h6"]
@ -84,3 +85,13 @@ def extract_text(html: str) -> str:
def truncate_string(text: str, words: int) -> str: def truncate_string(text: str, words: int) -> str:
return " ".join(islice(smart_split(text), words)) return " ".join(islice(smart_split(text), words))
def prefetch_for_listing(queryset: PageQuerySet) -> PageQuerySet:
"""
Prefetch a queryset ready for listing.
This should be a queryset method, but dealing with lots of
different page models is a pain.
"""
return queryset.select_related("hero_image", "hero_unsplash_photo")

View File

@ -10,7 +10,7 @@ from wagtail.models import Page
from wagtail.search.utils import parse_query_string from wagtail.search.utils import parse_query_string
from website.common.models import BaseContentPage from website.common.models import BaseContentPage
from website.common.utils import TocEntry from website.common.utils import TocEntry, prefetch_for_listing
from website.home.models import HomePage from website.home.models import HomePage
from .serializers import MIN_SEARCH_LENGTH, SearchParamsSerializer from .serializers import MIN_SEARCH_LENGTH, SearchParamsSerializer
@ -75,10 +75,8 @@ class SearchPage(RoutablePageMixin, BaseContentPage):
results = paginator.page(page_num) results = paginator.page(page_num)
# HACK: Search results aren't a queryset, so we can't call `.specific` on it. This forces it to one as efficiently as possible # HACK: Search results aren't a queryset, so we can't call `.specific` on it. This forces it to one as efficiently as possible
results.object_list = ( results.object_list = prefetch_for_listing(
results.object_list.get_queryset() results.object_list.get_queryset().specific()
.specific()
.select_related("hero_image", "hero_unsplash_photo")
) )
except EmptyPage: except EmptyPage: