0
\$\begingroup\$

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.

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.