Home > Blockchain >  How to render Page attributes in a model when displayed in StreamField?
How to render Page attributes in a model when displayed in StreamField?

Time:02-12

I have the following StructBlock and Page model:

class PostGrid(blocks.StructBlock):
    title = blocks.CharBlock()
    post_1 = blocks.PageChooserBlock()
    post_2 = blocks.PageChooserBlock()

    class Meta:
        template = 'post-grid.html'

class BlogIndex(Page):
    body = StreamField([('POSTS', PostGrid()),])

    class Meta:
        template = 'base.html'

class PostPage(Page):
    hero_title =  models.CharField(max_length=255)

I want to render the attributes of post_1 and post_2 in the body StreamField:

base.html:

{% for block in page.body %}
    {% include_block block %}
{% endfor %}

post-grid.html:

{{ value.post_1.url }}
{{ value.post_1.hero_title }}

value.post_1.url renders the URL fine. However, value.post_1.hero_title is blank.

How do I render the Page attributes?

CodePudding user response:

When you use PageChooserBlock() with no further options specified, Wagtail does not know in advance what the page type will be when retrieving it, and so it returns a basic Page instance which only consists of the basic fields common to all page types, such as title.

In this case, presumably only pages of PostPage should be allowed for these choosers, so you can specify that in the PageChooserBlock definition:

class PostGrid(blocks.StructBlock):
    title = blocks.CharBlock()
    post_1 = blocks.PageChooserBlock(page_type='myapp.PostPage')
    post_2 = blocks.PageChooserBlock(page_type='myapp.PostPage')
    # replace 'myapp' with your app name

With this change, the chooser will only allow selecting pages of type PostPage, and on the template, value.post_1 and value.post_2 will be returned as full PostPage instances, allowing you to use hero_title.

Alternatively, if you aren't able to make this change because there are multiple allowed page types, you can force it to fetch the full page object with .specific:

{% with value.post_1.specific as post_1 %}
    {{ post_1.url }}
    {{ post_1.hero_title }}
{% endwith %}

However, each call to specific will make an additional database query.

  • Related