You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:18:20