无法在模板 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>
我在 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>