Spec-Zone.ru › Wagtail

О блоках 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/stable/advanced_topics/boundblocks_and_values.html

Spec-Zone.ru

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