2

My requirement sounds simple, but I am struggling to make it work

In my wagtail project I have a BlogListingPage which has many child pages. I am trying to create a list of the children in a web page. Here is my code:

models.py

class BlogListingPage(Page):    
    ...
    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context['blog_pages'] = BlogDetailPage.objects.live().child_of(self)
        return context


class BlogDetailPage(Page):
    ...    
    blog_listing = models.ForeignKey(BlogListingPage,
                                     on_delete=models.PROTECT,
                                     blank=True,
                                     null=True,)

views.py

def blog(request):
    url = 'blog/blog_listing_page.html'
    context = {'data': BlogListingPage.objects.all()}
    return render(request, url, context)

blog_listing_page.html

{% block content %}
    {% for blog_listing in data %}
        {% for post in blog_listing.blogdetailpage %}
            <a href="{% pageurl post %}">{{ post.blog_title }}</a>
        {% endfor %}
    {% endfor %}
{% endblock content %}

I am lost in the fog of the django/wagtail pages/objects/querysets/all()/specific

Can someone please lead me to clear blue water?

Psionman
  • 3,084
  • 1
  • 32
  • 65
  • Does this answer your question? [Wagtail: Display a list of child pages inside a parent page](https://stackoverflow.com/questions/32429113/wagtail-display-a-list-of-child-pages-inside-a-parent-page) – timo.rieber Jan 26 '20 at 18:24
  • @Psionman: Amen to "I am lost in the fog of the django/wagtail pages/objects/querysets/all()/specific" (+ "views/tags/templates"). Appreciate your question, and the answer you received has helped make the fog here a bit less dense. I'm posting a followup request for clarification in a comment to the answer. – Joan Eliot Jan 13 '21 at 19:23

1 Answers1

4

A couple of suggestions regarding your approach:

  1. Having a foreign key from BlogDetailPage to BlogListingPage is not the Wagtail way to organise parent-child relationships. All Page objects already have a tree hierarchy and you should rely on that, otherwise you lose all the built-in tree handling provided by Wagtail.

    You should use the parent/subpage rules to specify how page types can be related to each other. In you case it would look something like:

    class BlogListingPage(Page):    
        subpage_types = ['myapp.BlogDetailPage']
    
    class BlogDetailPage(Page):
        parent_page_types = ['myapp.BlogListingPage']
    
  2. The get_context() method on BlogListingPage only runs when Wagtail is serving that specific page in a view. It doesn't run when you're iterating over these pages in your blog view. In order to access the children there, you need to do something like this:

    {% for blog_listing in data %}
        {% for post in blog_listing.get_children.live %}
            <a href="{% pageurl post %}">{{ post.blog_title }}</a>
        {% endfor %}
    {% endfor %}
    

    i.e., you need to use the get_children() method on the page to obtain it's children. live() further filters this to exclude unpublished pages. Note that this will only work if the blog posts are children (in the Wagtail page tree sense) of the listing page. specific() isn't important here if you're only using the post URL and title - it is relevant if you want to display fields that are part of your model rather than the base Page model.

solarissmoke
  • 30,039
  • 14
  • 71
  • 73
  • Thank you. A life saver. Great description of the solution – Psionman Jan 27 '20 at 08:33
  • 1
    Are there any performance considerations as to where you put the call to `get_children()` or its equivalent? The answer shows iteration via a tag in the template, but you could instead override the context in the Page model, [per the Wagtail docs](https://docs.wagtail.io/en/stable/topics/pages.html#customising-template-context) 'context['blog_entries'] = BlogPage.objects.child_of(self)
    return context'
    and then iterate over 'blog_entries' in the template. Is either approach faster/better?
    – Joan Eliot Jan 13 '21 at 19:29