FastAPI同时处理Form数据与文件上传时的Pydantic模型报错问题
问题:FastAPI中如何同时使用Pydantic模型接收Form数据并处理文件上传?
场景重现
用于校验Form数据的Pydantic模型:
from typing import Annotated from pydantic import BaseModel, StringConstraints, EmailStr class RouteBody(BaseModel): email: Annotated[EmailStr, StringConstraints( max_length = 255 )] password: Annotated[str, StringConstraints( max_length = 60 )]
对应的路由定义(同时处理Form数据与文件上传):
from fastapi import UploadFile, File @some_api_router.post("/some-route") async def handleRoute(routeBody: RouteBody = Form(), profilePicture: UploadFile = File(...)): return {"msg": "Route"}
测试时(通过SwaggerUI)出现错误:
error [{'type': 'model_attributes_type', 'loc': ('body', 'routeBody'), 'msg': 'Input should be a valid dictionary or object to extract fields from', 'input': '{"email":"user@example.com","password":"string"}'}]
已尝试的无效方案:
- 单独创建不含RouteBody的路由,功能正常
- 重新编写路由处理函数
- 调整参数顺序
- 将RouteBody拆分为单独参数(可行但参数过多时繁琐)
解决方案
核心原因
FastAPI无法直接将Pydantic模型作为Form()参数使用——Form数据以分散的键值对形式传递,而模型默认期望接收JSON结构的输入,因此会出现解析错误。
正确实现方式:通过依赖函数解析Form数据到模型
创建一个依赖函数,从Form中提取各个字段并实例化Pydantic模型,既保留模型的校验能力,又能与文件上传参数兼容:
from typing import Annotated from fastapi import Form, Depends, UploadFile, File from pydantic import BaseModel, StringConstraints, EmailStr class RouteBody(BaseModel): email: Annotated[EmailStr, StringConstraints(max_length=255)] password: Annotated[str, StringConstraints(max_length=60)] # 自定义依赖函数:收集Form字段并转换为RouteBody模型 def parse_route_body( email: Annotated[EmailStr, Form()], password: Annotated[str, Form(max_length=60)] ) -> RouteBody: return RouteBody(email=email, password=password) # 路由定义 @some_api_router.post("/some-route") async def handleRoute( route_body: RouteBody = Depends(parse_route_body), profile_picture: UploadFile = File(...) ): # 可直接使用校验后的route_body模型对象 return {"msg": "Success", "email": route_body.email}
优势
- 保留Pydantic模型的集中校验逻辑,避免参数过多时的代码冗余
- 完美兼容文件上传参数,符合Form数据的传递规范
- SwaggerUI会自动生成对应的表单字段,测试体验正常
内容的提问来源于stack exchange,提问作者ILIKETOLEARN
相关产品推荐
相关产品推荐

