Wagtail中动态向StreamField的StructBlock添加任务失败求助
解决Wagtail StreamField动态添加StructBlock时的ValueError问题
问题现象
在Wagtail项目中使用StreamField和StructBlock动态创建任务,用户提交表单参数后尝试添加新任务,无论是否使用json.dumps、是否调整结构,均触发错误:
ValueError: too many values to unpack (expected 2)
原代码如下:
models.py
tasks = StreamField([ ("task", blocks.StructBlock([ ("name", blocks.CharBlock(required=True, max_length=150)), ("description", blocks.RichTextBlock(required=False)), ("image", ImageChooserBlock(required=False)), ("subtasks", blocks.ListBlock(blocks.StructBlock([ ("name", blocks.CharBlock(required=True, max_length=150)), ("description", blocks.RichTextBlock(required=False)), ]))) ])) ], null=True, blank=True, use_json_field=True)
views.py(错误尝试)
def create_task(request, project_id): project = Project.objects.get(pk=project_id) # 错误尝试1:直接传字典 # new_task = { # "name": request.POST["task_name"], # "description": str(request.POST["task_description"]), # "image": None, # "subtasks": [], # } # project.tasks.append(json.dumps(new_task)) # 错误尝试2:传元组但用json.dumps序列化 # new_task = ('task',{ # "name": request.POST["task_name"], # "description": str(request.POST["task_description"]), # "image": None, # "subtasks": [], # }) # project.tasks.append(json.dumps(new_task)) # 错误尝试3:错误嵌套StructBlock结构 # new_task = { # 'type': 'task', 'value': { # 'type': 'name','value': request.POST['task_description'], # 'type': 'description','value': RichText(request.POST['task_description']), # 'type': 'image','value': None, # 'type': 'subtasks','value': [], # } # } # project.tasks.append(json.dumps(new_task)) project.save_revision( submitted_for_moderation=False, approved_go_live_at=None, changed=True, log_action=True, previous_revision=None, clean=True, ).publish() return JsonResponse({"status": "success"})
错误原因
StreamField的append方法要求传入的是**(block类型标识, 对应数据字典)**格式的元组,不需要手动用json.dumps序列化——Wagtail会自动处理序列化逻辑。之前的尝试要么格式不符合要求,要么多做了不必要的序列化操作,导致StreamBlock解析时无法正确拆分数据。
另外,StructBlock的数据是单层字典,不需要给每个子字段再套type和value的结构。
正确实现
修改views.py中的任务创建逻辑,直接传入符合要求的元组:
from wagtail.rich_text import RichText def create_task(request, project_id): project = Project.objects.get(pk=project_id) # 构造符合要求的任务项:(block类型名, 数据字典) new_task = ( "task", { "name": request.POST["task_name"], "description": RichText(request.POST["task_description"]), # 正确转换为RichText对象 "image": None, # 如果要传图片,需传入Image对象或ID,这里保持None "subtasks": [], } ) # 直接append元组,无需序列化 project.tasks.append(new_task) project.save_revision( submitted_for_moderation=False, approved_go_live_at=None, changed=True, log_action=True, previous_revision=None, clean=True, ).publish() return JsonResponse({"status": "success"})
额外说明
- 如果需要添加子任务,只需在
subtasks列表中传入符合子StructBlock格式的字典即可,例如:"subtasks": [ {"name": "子任务1", "description": RichText("子任务描述")}, {"name": "子任务2", "description": RichText("另一个子任务")} ] - 若要处理上传的图片,需先通过
Image.objects.get()获取对应的Image对象,再赋值给image字段,不能直接传文件对象或路径。
内容的提问来源于stack exchange,提问作者ohad guetta
相关产品推荐
相关产品推荐

