无法在模板 Wagtail 中的 StreamBlock 内呈现 Listblock

Unable to render Listblock inside StreamBlock in template Wagtail

我在 Listblock 中有 StructBlock,所有这些都位于 class BannerBlock 中,如下所示:

class BannerBlock(blocks.StreamBlock):
    """
    Blocks for displaying individual banners
    """
    
    banners = blocks.ListBlock(
        blocks.StructBlock(
            [
                ('image', ImageChooserBlock(required=True)),
                ('title', blocks.CharBlock(required=True, max_length=128)),
                ('description', blocks.CharBlock(required=True, max_length=1024)),
                ('link', blocks.URLBlock(required=False)),
            ]
        )
    )
    
    class Meta:
        template = "home/banner_block.html"
        icon = "placeholder"
        label = "Banners"

模板Banner_block如下:

{% load wagtailimages_tags %}

<!-- Banner -->
<div id="banner">
    {% for banner in self.banners %}
        <article data-position="bottom right">
            <div class="inner">
                {% image banner.image original as image %}
                <img src="{{ image.url }}" alt="">
                <div class="features">
                    <a href="{{ banner.link.url }}" class="c-accent alt no-bg">
                    <h2>{{ banner.title }}</h2>
                    <p>{{ banner.description }}</p>
                    </a>
                </div>
            </div>
        </article>
    {% endfor %}
</div>

最后,我尝试按如下方式呈现每个横幅 (Listblock):

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

但是,每个列表块都呈现为纯文本列表项。 如何正确渲染每个项目? 谢谢。

我假设您页面模型上的 banners_collection 字段定义为:

banners_collection = StreamField(BannerBlock())

您指定要在 StreamField 的顶层使用的 StreamBlock,而不是

的更基本设置
some_stream = StreamField([
    ('first_block_type', some_block_definition),
    ('another_block_type', some_block_definition),
])

在其中为 StreamField 传递块列表以从中创建流。这意味着当您访问 page.banners_collection 时,它将为您提供 BannerBlock 值的单个实例。当您使用 for block in page.banners_collection 遍历此值时,您实际上是在流中取回 ListBlock 值,并使用 include_block 单独呈现它们 - 绕过您为 BannerBlock 设置的模板。您的 ListBlock 值没有自己的模板,因此它们最终使用默认呈现。

如果您对整个 BannerBlock 值调用 include_block

{% include_block page.banners_collection %}

然后它将使用您的模板。但是,还有一个次要问题 - 在

{% for banner in self.banners %}

self.banners 无效,因为流值表现为序列,而不是字典。您不能按名称查找 banners 个子项 - 您需要遍历子项列表以找到 banners 类型的子项。 (除非,在您的情况下,您可以跳过该检查,因为 banners 是流中唯一可用的块类型)。正确的模板代码如下所示:

<div id="banner">
    {% for block in self %}
        {# the 'block' object here has properties block_type (which is always 'banners' here) and value #}
        {% for banner in block.value %}
            {# banner is a StructBlock value, with image, title, description, link properties #}
            <article data-position="bottom right">
                <div class="inner">
                    {% image banner.image original as image %}
                    ...
               </div>
           </article>
        {% endfor %}
    {% endfor %}
</div>

但是,您确定除了 StreamBlock 之外还需要 ListBlock 吗? StreamBlock 已经是一系列块,因此 StreamBlock 中的 ListBlock 会为您提供 横幅列表 的列表。如果您将 BannerBlock 值简化为

class BannerBlock(blocks.StreamBlock):
    """
    Blocks for displaying individual banners
    """
    
    banner = blocks.StructBlock(
        [
            ('image', ImageChooserBlock(required=True)),
            ('title', blocks.CharBlock(required=True, max_length=128)),
            ('description', blocks.CharBlock(required=True, max_length=1024)),
            ('link', blocks.URLBlock(required=False)),
        ]
    )
    
    class Meta:
        template = "home/banner_block.html"
        icon = "placeholder"
        label = "Banners"

那么 BannerBlock 作为一个整体将是一个横幅列表,模板将变为

<div id="banner">
    {% for block in self %}
        {# block.value is now a StructBlock value #}
        <article data-position="bottom right">
            <div class="inner">
                {% image block.value.image original as image %}
                ...
           </div>
       </article>
    {% endfor %}
</div>