#python #django-templates #wagtail
#python #django-шаблоны #wagtail
Вопрос:
У меня есть StructBlock внутри Listblock, все из которых находятся внутри 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 %}
Однако каждый блок списка отображается в виде обычного текста, как элементы списка.
Как мне правильно отобразить каждый элемент?
Спасибо.
Ответ №1:
Я предполагаю banners_collection
, что поле в вашей модели страницы определено как:
banners_collection = StreamField(BannerBlock())
где вы указываете StreamBlock для использования на верхнем уровне StreamField, а не для более простой настройки
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
значений нет собственного шаблона, поэтому в конечном итоге они используют рендеринг по умолчанию.
Если вы вызываете include_block
значение BannerBlock в целом:
{% 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>
Однако вы уверены, что вам нужен ListBlock в дополнение к StreamBlock? StreamBlock уже представляет собой последовательность блоков, поэтому ListBlock внутри StreamBlock выдает вам список списков баннеров. Если вы упростили значение 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>