Добавление структурного блока Wagtail в Streamfield

Есть ли хороший способ добавить StructBlock в существующее StreamField? Я создаю страницу ссылок, где пользователи, не являющиеся администраторами, могут добавлять свои собственные ссылки. Я хотел бы иметь возможность добавлять LinkBlock, используя данные формы. Я прилагаю то, что у меня есть сейчас, и в настоящее время прохожу через исходный код Wagtail, чтобы лучше понять, как создаются блоки.

class LinkBlock(blocks.StructBlock):
    title = blocks.CharBlock(required=True, help_text="Link title")
    url = blocks.URLBlock(
        required=True,
        help_text="Link URL",
    )



class LinksPage(Page):
    links = StreamField(
        [
            ("link", LinkBlock()),
        ],
        blank=True,
        use_json_field=True,
        max_length=20
    )

    content_panels = Page.content_panels + [
        FieldPanel("links"),
    ]

# Adding dynamic links with form data
links_page.links.append(
    (
        "link",
        {
            "title": form.cleaned_data["title"],
            "url": form.cleaned_data["url"],
            "link_type": form.cleaned_data["link_type"],
            "color_scheme": form.cleaned_data["color_scheme"],
        },
    )
)

try:
    # TODO: Investigate why this is necessary
    # links_page.links._raw_data = [lnk for lnk in links_page.links._raw_data if lnk is not None]
    # without the filter above, we get a TypeError when trying to save the page
    links_page.save()
except TypeError as e:
    logger.error(f"Error saving link: {e}")
    raise e

"""
Example stack trace:

  File "../.venv/lib/python3.13/site-packages/wagtail/blocks/stream_block.py", line 680, in __getitem__
    self._prefetch_blocks(raw_value["type"])
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "../.venv/lib/python3.13/site-packages/wagtail/blocks/stream_block.py", line 710, in _prefetch_blocks
    raw_values = OrderedDict(

  File "../.venv/lib/python3.13/site-packages/wagtail/blocks/stream_block.py", line 713, in <genexpr>
    if raw_item["type"] == type_name and self._bound_blocks[i] is None
       ~~~~~~~~^^^^^^^^
TypeError: 'NoneType' object is not subscriptable
"""

После того, как мы поработали, похоже, что этот метод работает для добавления StructBlock:

links = [(lnk.block_type, lnk.value) for lnk in links_page.links]
links.append(
    (
        "link",
        {
            "title": form.cleaned_data["title"],
            "url": form.cleaned_data["url"],
            "link_type": form.cleaned_data["link_type"],
            "color_scheme": form.cleaned_data["color_scheme"],
        },
    )
)
links_page.links = links
Однако в

документации Wagtail вроде бы указано, что простой append с кортежем (тип блока, данные) должен работать. Буду благодарен за понимание.

Возникшая у вас ситуация TypeError говорит о том, что после добавления некоторые блоки могли оказаться None или неправильно отформатированными. Это может произойти, если данные не были правильно переданы в блок.

Вместо того чтобы вручную фильтровать _raw_data или переназначать links_page.links непосредственно список кортежей, следует использовать метод StreamField's для обновления его данных. Попробуйте перейти от этого подхода

к следующему
# firstly prepare the form data for the new link
link_data = {
    "title": form.cleaned_data["title"],
    "url": form.cleaned_data["url"],
    "link_type": form.cleaned_data["link_type"],
    "color_scheme": form.cleaned_data["color_scheme"],
}

# now append the new link as a tuple (type, data)
links_page.links.append(
    ("link", link_data)
)

# save the page
try:
    links_page.save()
except TypeError as e:
    logger.error(f"Error saving link: {e}")
    raise e

если ошибка сохраняется, проверьте внутреннее представление StreamField's, осмотрев links_page.links до и после добавления, чтобы отладить любые проблемы с форматом данных.

Вернуться на верх