Spec-Zone.ru › Wagtail 3

О блоках StreamField BoundBlocks и значениях

Все типы блоков StreamField принимают параметр template для определения, как они будут отображаться на странице. Однако для блоков, которые обрабатывают базовые типы данных Python, такие как CharBlock и IntegerBlock, существуют ограничения на область действия шаблона, так как эти встроенные типы (str, int и т. д.) не могут быть «обучены» своему отображению в шаблоне. Пример такого блока:

class HeadingBlock(blocks.CharBlock):
    class Meta:
        template = 'blocks/heading.html'

где blocks/heading.html состоит из:

<h1>{{ value }}</h1>

Это даёт нам блок, который ведет себя как обычное текстовое поле, но оборачивает свой вывод тегами <h1> при каждом отображении:

class BlogPage(Page):
    body = StreamField([
        # ...
        ('heading', HeadingBlock()),
        # ...
    ], use_json_field=True)
{% load wagtailcore_tags %}

{% for block in page.body %}
    {% if block.block_type == 'heading' %}
        {% include_block block %}  {# This block will output its own <h1>...</h1> tags. #}
    {% endif %}
{% endfor %}

Такая организация — значение, которое предположительно представляет собой простую текстовую строку, но имеет собственное пользовательское HTML-представление при выводе в шаблоне — обычно очень сложно реализовать на Python, но здесь всё работает, потому что элементы, полученные при итерации по StreamField, на самом деле не являются «родными» значениями блоков. Вместо этого каждый элемент возвращается как экземпляр BoundBlock — объект, представляющий пару значения и определения блока. Следя за определением блока, BoundBlock всегда знает, какой шаблон нужно использовать для отображения. Чтобы получить основное значение — в данном случае текстовое содержимое заголовка — вам нужно обратиться к block.value. Действительно, если вы выведете {% include_block block.value %} на странице, вы увидите, что оно отобразится как обычный текст без тегов <h1>.

(Точнее, элементы, возвращаемые при итерации по StreamField, являются экземплярами класса StreamChild, который предоставляет свойство block_type и value.)

Опытные разработчики Django могут найти полезным сравнение с классом BoundField в рамках фреймворка форм Django, который представляет собой пару значения поля формы и его соответствующего определения поля формы, и, следовательно, знает, как отобразить значение как поле HTML-формы.

Большую часть времени вам не нужно беспокоиться об этих внутренних деталях; Wagtail будет использовать отображение в шаблоне там, где вы ожидаете этого. Однако есть определённые случаи, когда иллюзия не полная — именно при обращении к дочерним элементам ListBlock или StructBlock. В этих случаях нет обертки BoundBlock, и поэтому нельзя полагаться на то, что элемент знает своё отображение в шаблоне. Например, рассмотрим следующую настройку, где наш HeadingBlock является дочерним элементом StructBlock:

class EventBlock(blocks.StructBlock):
    heading = HeadingBlock()
    description = blocks.TextBlock()
    # ...

    class Meta:
        template = 'blocks/event.html'

В blocks/event.html:

{% load wagtailcore_tags %}

<div class="event {% if value.heading == 'Party!' %}lots-of-balloons{% endif %}">
    {% include_block value.heading %}
    - {% include_block value.description %}
</div>

В этом случае value.heading возвращает простое строковое значение, а не BoundBlock; это необходимо, потому что в противном случае сравнение в {% if value.heading == 'Party!' %} никогда не выполнится. Это, в свою очередь, означает, что {% include_block value.heading %} отображается как простая строка без тегов <h1>. Чтобы получить HTML-отображение, нужно явно получить экземпляр BoundBlock через value.bound_blocks.heading:

{% load wagtailcore_tags %}

<div class="event {% if value.heading == 'Party!' %}lots-of-balloons{% endif %}">
    {% include_block value.bound_blocks.heading %}
    - {% include_block value.description %}
</div>

На практике, вероятно, было бы более естественно и удобочитаемо сделать тег <h1> явным в шаблоне EventBlock:

{% load wagtailcore_tags %}

<div class="event {% if value.heading == 'Party!' %}lots-of-balloons{% endif %}">
    <h1>{{ value.heading }}</h1>
    - {% include_block value.description %}
</div>

Это ограничение не относится к значениям StructBlock и StreamBlock как дочерним элементам StructBlock, так как Wagtail реализует их как сложные объекты, знающие своё собственное отображение в шаблоне, даже если они не обернуты в BoundBlock. Например, если StructBlock вложен в другой StructBlock, как в:

class EventBlock(blocks.StructBlock):
    heading = HeadingBlock()
    description = blocks.TextBlock()
    guest_speaker = blocks.StructBlock([
        ('first_name', blocks.CharBlock()),
        ('surname', blocks.CharBlock()),
        ('photo', ImageChooserBlock()),
    ], template='blocks/speaker.html')

тогда {% include_block value.guest_speaker %} в шаблоне EventBlock получит отображение в шаблоне из blocks/speaker.html как предполагалось.

Вкратце, взаимодействия между BoundBlocks и простыми значениями работают по следующим правилам:

  1. При итерации по значению StreamField или StreamBlock (как в {% for block in page.body %}) вы получите последовательность BoundBlocks.
  2. Если у вас есть экземпляр BoundBlock, вы можете получить простое значение как block.value.
  3. Обращение к дочернему элементу StructBlock (как в value.heading) вернёт простое значение; чтобы получить BoundBlock, используйте value.bound_blocks.heading.
  4. Аналогично, обращение к дочерним элементам ListBlock (например, for item in value) вернёт простые значения; чтобы получить BoundBlocks, используйте value.bound_blocks.
  5. Значения StructBlock и StreamBlock всегда знают, как отобразить свои собственные шаблоны, даже если у вас есть только простое значение, а не BoundBlock.

Изменено в версии 2.16: Значение ListBlock теперь предоставляет свойство bound_blocks; ранее это был обычный список Python с дочерними значениями.

© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/v3.0.3/advanced_topics/boundblocks_and_values.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API