Добавление структурного блока 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
до и после добавления, чтобы отладить любые проблемы с форматом данных.