如何用FastAPI+Pydantic BaseModel验证解析HTMX表单数据
在FastAPI中用Pydantic BaseModel处理HTMX表单数据
核心结论
完全可以用Pydantic BaseModel定义表单数据结构,不必逐个字段使用Annotated[类型, Form()]的繁琐方式。
可行方案
方案一:自定义依赖项解析表单数据
通过自定义依赖函数,从请求中获取表单数据并映射到BaseModel:
from fastapi import APIRouter, Request, Depends from fastapi.templating import Jinja2Templates from pydantic import BaseModel router = APIRouter() templates = Jinja2Templates(directory="templates") # 定义表单数据模型 class FormData(BaseModel): testing: str # 自定义依赖:解析表单数据到模型 async def parse_form_data(request: Request) -> FormData: form_data = await request.form() # 将ImmutableMultiDict转为字典,传入BaseModel完成验证 return FormData(**dict(form_data)) @router.post("/post") async def index_post(request: Request, data: FormData = Depends(parse_form_data)): print(data.testing) return templates.TemplateResponse("main.html", {'request': request})
方案二:使用Body指定媒体类型
直接通过Body参数指定媒体类型为application/x-www-form-urlencoded,FastAPI会自动将表单数据解析到BaseModel:
from fastapi import APIRouter, Request, Body from fastapi.templating import Jinja2Templates from pydantic import BaseModel router = APIRouter() templates = Jinja2Templates(directory="templates") class FormData(BaseModel): testing: str @router.post("/post") async def index_post(request: Request, data: FormData = Body(..., media_type="application/x-www-form-urlencoded")): print(data.testing) return templates.TemplateResponse("main.html", {'request': request})
失败原因说明
直接使用Annotated[FormData, Form()]无效,因为Form()是为单个字段设计的,FastAPI无法自动将多字段的表单数据映射到BaseModel实例。上述两种方法分别通过手动解析表单数据、指定正确的媒体类型,解决了映射问题。
HTMX场景适配
HTMX默认发送application/x-www-form-urlencoded格式的请求,上述方案完全适配该场景,无需修改前端代码。
内容的提问来源于stack exchange,提问作者Shamus McKeown
相关产品推荐
相关产品推荐

