I'm using Django and Wagtail 5.x to build a blog. At this point, I'm trying to increase my understanding of query optimization and decrease the number of necessary db queries by implementing select_related
. To my knowledge, I can use select_related
to essentially chain related queries. In other words, when I'm accessing the db for the categories associated with CarHubPage
, I can also get the posts related to those categories simultaneously. I assume it caches the results, so when I actually access the category's posts in the template, it will not require another db lookup. Is my understanding correct?
However, testing with and without select_related
produces the same results (testing with Django toolbar). So I need help making sense of the inner workings and whether my approach/understanding is correct.
What's the best approach here?
class CarHubPage(Page):
intro = RichTextField()
youtube_embeds = StreamField(
[
(
"Youtube",
YoutubeEmbedBlock(),
)
],
use_json_field=True,
null=True,
)
content_panels = Page.content_panels + [
FieldPanel("intro"),
FieldPanel("youtube_embeds"),
]
parent_page_types = ["BlogIndexPage"]
subpage_types = ["CategoryPage"]
def get_context(self, request, *args, **kwargs):
context = super().get_context(request)
context["posts_per_category"] = (
self.get_children().live().specific().select_related("category_posts")
)
return context
class CategoryPage(Page):
intro = RichTextField()
parent_page_types = ["BlogIndexPage", "CarHubPage"]
subpage_types = ["BlogPage"]
content_panels = Page.content_panels + [
FieldPanel("intro"),
]
def get_context(self, request, *args, **kwargs):
context = super().get_context(request)
return context
class BlogPage(Page):
category = ParentalKey(
CategoryPage,
on_delete=models.CASCADE,
related_name="category_posts",
blank=True,
)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
)
date = models.DateField(default=date.today)
snippet = models.CharField(
max_length=200,
help_text="Excerpt used in the article's preview card.",
)
featured_image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.CASCADE,
)
tags = ClusterTaggableManager(through="BlogPageTag", blank=True)
body = RichTextField()
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("author"),
FieldPanel("date"),
FieldPanel("tags"),
],
heading="Blog Information",
),
FieldPanel("snippet"),
FieldPanel("featured_image"),
FieldPanel("body"),
]
parent_page_types = ["CategoryPage"]
subpage_types = []
def save(self, clean=True, user=None, log_action=False, **kwargs):
self.category = self.get_parent()
return super().save(clean, user, log_action, **kwargs)
Specifically focusing on:
def get_context(self, request, *args, **kwargs):
context = super().get_context(request)
context["posts_per_category"] = (
self.get_children().live().specific().select_related("category_posts")
)
return context
Template (just for testing purposes at the moment):
{% for cat in posts_per_category %}
<div class="row">
<div class="col-lg-6">
<h2 class="mt-4">{{ cat.title }}</h2>
</div>
</div>
<div class="row">
{% for post in cat.category_posts.all %}
{{ post.specific.snippet }}
{{ post.specific.title }}
{% endfor %}
</div>
{% endfor %}
I've also tried, self.get_children().live().specific().select_related("child")
- but I believe select_related
only works with a ForeignKey relationship?
Thank you. Any other advice is also appreciated.