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

如何通过Pydantic从HTML表单返回嵌套列表结构数据?

解决FormData转嵌套Pydantic模型的问题

要实现将扁平的FormData解析为包含ingredients嵌套数组的结构,需要手动处理表单数据的分组与转换,因为FastAPI默认不会自动将重复字段映射为嵌套数组。以下是具体实现步骤:

1. 编写表单数据解析辅助函数

该函数负责将扁平的FormData字段分组,转换为符合RecipeUpdate模型的字典结构:

from fastapi import FormData
from typing import Optional, Dict, List

def parse_form_to_recipe_update(form_data: FormData) -> Dict:
    # 提取基础字段
    recipe_data = {
        "name": form_data.get("name"),
        "description": form_data.get("description")
    }
    
    # 定义食材相关字段的顺序
    ing_field_names = ["ing_id", "ing_qty", "ing_type", "ing_name"]
    ingredients = []
    
    # 获取每个食材字段的所有值(重复字段会返回列表)
    field_value_lists = {field: form_data.getlist(field) for field in ing_field_names}
    
    # 计算食材条目数量(取最长字段列表的长度)
    total_ingredients = max(len(vals) for vals in field_value_lists.values())
    
    # 按索引分组,构建每个食材的字典
    for idx in range(total_ingredients):
        ing_dict = {}
        for field in ing_field_names:
            # 取出对应索引的值,不存在则设为None
            raw_val = field_value_lists[field][idx] if idx < len(field_value_lists[field]) else None
            
            # 类型转换:将ID和数量转为整数(处理表单字符串)
            if field in ["ing_id", "ing_qty"] and raw_val is not None:
                try:
                    ing_dict[field] = int(raw_val)
                except ValueError:
                    ing_dict[field] = None
            else:
                ing_dict[field] = raw_val
        
        ingredients.append(ing_dict)
    
    recipe_data["ingredients"] = ingredients
    return recipe_data

2. 修改FastAPI路由

在路由中调用解析函数,将转换后的数据传入Pydantic模型进行验证:

from fastapi import APIRouter, Request, Depends
from sqlalchemy.orm import Session
from your_module import get_db, RecipeUpdate  # 替换为实际的导入路径

router = APIRouter()

@router.post("/edit/{recipe_id}", response_model=RecipeUpdate)
async def edit_select_recipe(request: Request, recipe_id: int, db: Session = Depends(get_db)):
    form_data = await request.form()
    # 解析表单数据为模型所需结构
    parsed_data = parse_form_to_recipe_update(form_data)
    # 用Pydantic模型验证数据
    recipe_update = RecipeUpdate(**parsed_data)
    
    # 此处添加数据库更新逻辑,例如:
    # db.query(Recipe).filter(Recipe.id == recipe_id).update(recipe_update.dict(exclude_unset=True))
    # db.commit()
    
    return recipe_update

关键说明

  • 重复字段处理:使用form_data.getlist(field)获取重复字段的所有值,而非get()(后者仅返回最后一个值)。
  • 类型转换:表单数据默认是字符串类型,需手动将ing_id和ing_qty转为整数,并处理转换失败的情况。
  • 兼容性:即使部分食材字段缺失,代码会自动将对应值设为None,符合Pydantic模型中Optional的定义。

内容的提问来源于stack exchange,提问作者Chris Plummer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:36:05