求助:Wagtail中给含嵌套ListBlock的StreamField代码赋值失败
Wagtail代码创建页面填充嵌套ListBlock失败的解决方案
问题背景
我有一个带StreamField(body)的Wagtail页面,以及自定义的CardBlock块,代码如下:
from wagtail import blocks from wagtail.models import Page class CardBlock(blocks.StructBlock): title = blocks.CharBlock() description = blocks.CharBlock() # 其他字段... class CardListBlock(blocks.StructBlock): cards = blocks.ListBlock(CardBlock()) class CustomPage(Page): # 其他字段... body = blocks.StreamField([ ('card_block', CardBlock()), ('card_list', CardListBlock()) ])
需要通过代码创建CustomPage并填充card_list,但尝试多种写法后要么报错,要么数据无法保存到数据库。
尝试过的无效写法及结果
直接传入列表:
page = CustomPage() page.body = [ ('card_block', {'title': 'foo', 'description': 'bar'}), ('card_list', {'cards': [{'title': 'foo', 'description': 'bar'}]}) ]报错:
AttributeError: 'list' object has no attribute 'bound_blocks'用
ListValue包裹:from wagtail.blocks.list_block import ListValue page.body = [ ('card_block', {'title': 'foo', 'description': 'bar'}), ('card_list', {'cards': ListValue([{'title': 'foo', 'description': 'bar'}])}) ]执行无报错,但数据库中
card_list为空。结合
StructValue:from wagtail.blocks.struct_block import StructValue ('card_list', { 'cards': ListValue([StructValue([('title', 'foo'), ('description', "bar")])]) })结果依然为空。
模仿后台数据格式:
('card_list', { 'cards': ListValue([{ "type": "item", "value": {"title": "foo", "description": "bar"}, "id": "uuid" }]) })仍然无效。
正确解决方案
核心是让嵌套块的数据通过对应块实例的to_python方法处理,确保转换成Wagtail内部能识别的格式。
方法1:单个块处理嵌套数据
# 创建页面实例(需填充必填字段如title、slug) page = CustomPage(title="测试页面", slug="test-page") # 获取对应块实例 card_list_block = CustomPage.body.stream_block.child_blocks['card_list'] card_block = card_list_block.child_blocks['cards'].child_block # 处理卡片数据,用CardBlock的to_python转换每个卡片 cards_data = [ card_block.to_python({'title': 'foo', 'description': 'bar'}), card_block.to_python({'title': 'baz', 'description': 'qux'}) ] # 处理card_list数据 card_list_data = card_list_block.to_python({'cards': cards_data}) # 赋值并保存 page.body = [ ('card_block', {'title': 'foo', 'description': 'bar'}), ('card_list', card_list_data) ] page.save()
方法2:整体转换StreamField数据
更简洁的方式,直接用整个StreamField块的to_python方法处理全部数据:
body_data = [ ('card_block', {'title': 'foo', 'description': 'bar'}), ('card_list', {'cards': [ {'title': 'foo', 'description': 'bar'}, {'title': 'baz', 'description': 'qux'} ]}) ] page = CustomPage(title="测试页面", slug="test-page") # 用stream_block的to_python处理整个body数据 page.body = CustomPage.body.stream_block.to_python(body_data) page.save()
原因说明
直接传入字典或列表时,嵌套的ListBlock没有绑定到对应的块实例,无法完成数据序列化。通过块的to_python方法处理后,数据会被转换成Wagtail内部需要的StructValue和ListValue实例,确保能正确存储到数据库。
内容的提问来源于stack exchange,提问作者ZephyRr Mahesh
相关产品推荐
相关产品推荐

