Optimise for cache hits
Don't select/prefetch for listing, because we cache the entire listing item. This makes the main query more efficient, thus page loads faster.
This commit is contained in:
parent
fa85c8ba80
commit
b515b6368c
6 changed files with 24 additions and 41 deletions
|
@ -9,7 +9,7 @@ from wagtail.admin.panels import FieldPanel
|
||||||
from wagtailautocomplete.edit_handlers import AutocompletePanel
|
from wagtailautocomplete.edit_handlers import AutocompletePanel
|
||||||
|
|
||||||
from website.common.models import BaseContentPage, BaseListingPage
|
from website.common.models import BaseContentPage, BaseListingPage
|
||||||
from website.common.utils import TocEntry, prefetch_for_listing
|
from website.common.utils import TocEntry
|
||||||
from website.common.views import ContentPageFeed
|
from website.common.views import ContentPageFeed
|
||||||
from website.contrib.singleton_page.utils import SingletonPageCache
|
from website.contrib.singleton_page.utils import SingletonPageCache
|
||||||
|
|
||||||
|
@ -43,12 +43,11 @@ class BlogPostListPage(BaseListingPage):
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_listing_pages(self) -> models.QuerySet:
|
def get_listing_pages(self) -> models.QuerySet:
|
||||||
return prefetch_for_listing(
|
return (
|
||||||
BlogPostPage.objects.descendant_of(self)
|
BlogPostPage.objects.descendant_of(self)
|
||||||
.live()
|
.live()
|
||||||
.public()
|
.public()
|
||||||
.order_by("-date", "title")
|
.order_by("-date", "title")
|
||||||
.prefetch_related("tags")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -127,11 +126,10 @@ class BlogPostCollectionPage(BaseListingPage):
|
||||||
subpage_types = [BlogPostPage]
|
subpage_types = [BlogPostPage]
|
||||||
|
|
||||||
def get_listing_pages(self) -> models.QuerySet:
|
def get_listing_pages(self) -> models.QuerySet:
|
||||||
return prefetch_for_listing(
|
return (
|
||||||
BlogPostPage.objects.child_of(self)
|
BlogPostPage.objects.child_of(self)
|
||||||
.live()
|
.live()
|
||||||
.public()
|
.public()
|
||||||
.prefetch_related("tags")
|
|
||||||
.order_by("-date", "title")
|
.order_by("-date", "title")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ from .utils import (
|
||||||
count_words,
|
count_words,
|
||||||
extract_text,
|
extract_text,
|
||||||
get_table_of_contents,
|
get_table_of_contents,
|
||||||
prefetch_for_listing,
|
|
||||||
truncate_string,
|
truncate_string,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -190,9 +189,7 @@ class BaseListingPage(RoutablePageMixin, BaseContentPage):
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get_listing_pages(self) -> models.QuerySet:
|
def get_listing_pages(self) -> models.QuerySet:
|
||||||
return prefetch_for_listing(
|
return self.get_children().live().public().specific().order_by("title")
|
||||||
self.get_children().live().public().specific().order_by("title")
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_paginator_page(self) -> PaginatorPage:
|
def get_paginator_page(self) -> PaginatorPage:
|
||||||
paginator = Paginator(self.get_listing_pages(), per_page=self.PAGE_SIZE)
|
paginator = Paginator(self.get_listing_pages(), per_page=self.PAGE_SIZE)
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
{% load wagtailcore_tags cache util_tags %}
|
{% load wagtailcore_tags cache util_tags %}
|
||||||
|
|
||||||
<article class="media listing-item">
|
{% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "listing-item" page.id request.is_preview %}
|
||||||
<div class="columns">
|
<article class="media listing-item">
|
||||||
<figure class="media-left column is-3 image-column">
|
<div class="columns">
|
||||||
{% if page.list_image_url %}
|
<figure class="media-left column is-3 image-column">
|
||||||
<a href="{% pageurl page %}" class="image">
|
{% if page.list_image_url %}
|
||||||
<img src="{{ page.list_image_url }}" loading="lazy" decoding="async" />
|
<a href="{% pageurl page %}" class="image">
|
||||||
</a>
|
<img src="{{ page.list_image_url }}" loading="lazy" decoding="async" />
|
||||||
{% endif %}
|
</a>
|
||||||
</figure>
|
{% endif %}
|
||||||
<div class="media-content column">
|
</figure>
|
||||||
<div>
|
<div class="media-content column">
|
||||||
<h2 class="title is-3"><a href="{% pageurl page %}">{{ page.title }}</a></h2>
|
<div>
|
||||||
{% include "common/content-details.html" %}
|
<h2 class="title is-3"><a href="{% pageurl page %}">{{ page.title }}</a></h2>
|
||||||
{% cache FRAGMENT_CACHE_TTL|jitter:FRAGMENT_CACHE_TTL_JITTER "summary" page.id request.is_preview %}
|
{% include "common/content-details.html" %}
|
||||||
<p>{{ page.summary }}</p>
|
<p>{{ page.summary }}</p>
|
||||||
{% endcache %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</article>
|
{% endcache %}
|
||||||
|
|
|
@ -87,16 +87,6 @@ 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")
|
|
||||||
|
|
||||||
|
|
||||||
def heading_id(heading: str) -> str:
|
def heading_id(heading: str) -> str:
|
||||||
"""
|
"""
|
||||||
Convert a heading into an identifier which is valid for a HTML id attribute
|
Convert a heading into an identifier which is valid for a HTML id attribute
|
||||||
|
|
|
@ -6,7 +6,7 @@ from wagtail.models import Page
|
||||||
|
|
||||||
from website.common.models import BasePage
|
from website.common.models import BasePage
|
||||||
|
|
||||||
FRAGMENT_CACHES = {"summary", "content-details"}
|
FRAGMENT_CACHES = {"listing-item", "content-details"}
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("after_edit_page")
|
@hooks.register("after_edit_page")
|
||||||
|
|
|
@ -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, prefetch_for_listing
|
from website.common.utils import TocEntry
|
||||||
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
|
||||||
|
@ -76,9 +76,7 @@ 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 = prefetch_for_listing(
|
results.object_list = results.object_list.get_queryset().specific()
|
||||||
results.object_list.get_queryset().specific()
|
|
||||||
)
|
|
||||||
|
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
Loading…
Reference in a new issue