FastAPI使用multipart/form-data同时上传文件与JSON数据报错
错误原因
- 你的
Banner模型未继承Pydantic的BaseModel,本身不符合FastAPI参数校验的基础要求 - FastAPI默认无法在
multipart/form-data类型的请求中直接解析Pydantic模型参数:multipart请求里的非文件字段默认是字符串类型,不会自动反序列化为JSON结构的模型对象。
解决方案
方案1:手动解析Form中的JSON字符串(最通用)
先修正Banner模型定义,补全BaseModel继承:
from pydantic import BaseModel from fastapi import UploadFile, File, Form import json # 修正后的Pydantic模型 class Banner(BaseModel): title: str text: str
修改路由逻辑,把Banner参数改为字符串类型的Form字段,接收后手动解析为模型:
@router.post('', status_code=201) async def create_banner( # 接收前端序列化后的JSON字符串 banner: str = Form(...), photo: UploadFile = File(...) ): # 反序列化为Banner模型对象 try: banner_data = Banner.parse_raw(banner) except Exception as e: return {"code": 400, "msg": "banner参数格式错误"} return await Banners.create(banner_data.dict())
前端调用说明:请求时需要将banner对应的JSON对象序列化为字符串,放在form表单的banner字段中,photo字段上传文件即可。
方案2:拆分JSON为独立Form字段(更简单,适合字段少的场景)
如果Banner的字段数量少,可以直接拆分为单独的Form参数,不需要传JSON字符串:
@router.post('', status_code=201) async def create_banner( title: str = Form(...), text: str = Form(...), photo: UploadFile = File(...) ): banner_data = Banner(title=title, text=text) return await Banners.create(banner_data.dict())
前端调用说明:直接在form表单中传title、text、photo三个字段即可,不需要做JSON序列化。
方案3:封装依赖统一解析(适合多接口复用场景)
如果有多个接口都需要同时传文件和JSON模型,可以封装通用的依赖函数简化代码:
from fastapi import Depends, HTTPException from pydantic import ValidationError, BaseModel import json def form_json(model: type[BaseModel]): async def _form_json(data: str = Form(...)): try: return model.parse_raw(data) except (json.JSONDecodeError, ValidationError): raise HTTPException(status_code=400, detail="参数格式错误") return Depends(_form_json)
路由中直接使用即可:
@router.post('', status_code=201) async def create_banner( banner: Banner = form_json(Banner), photo: UploadFile = File(...) ): return await Banners.create(banner.dict())
内容的提问来源于stack exchange,提问作者Hahan't
相关产品推荐
相关产品推荐

