使用FastAPI+Pydantic获取HTML表单数据时遭遇422错误
解决FastAPI接收HTML表单数据时的422 Unprocessable Entity错误
错误详情
{"detail":[{"loc":["body"],"msg":"value is not a valid dict","type":"type_error.dict"}]}
问题原因
HTML表单默认以application/x-www-form-urlencoded格式提交数据,但FastAPI的Pydantic模型参数默认期望接收JSON格式(application/json)的请求体,两者格式不匹配,因此抛出类型错误。
方案一:使用Form逐个接收表单字段
修改main.py的/predict接口,用Form装饰器逐个获取表单字段,再映射到Health模型:
from fastapi import FastAPI, Form, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles from health import Health import uvicorn import pickle import json import warnings warnings.filterwarnings('ignore') app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory='templates') @app.get('/', response_class=HTMLResponse) def main(request: Request): return templates.TemplateResponse('index.html', {'request': request}) @app.post('/predict', response_class=HTMLResponse) def predict( gender: str = Form(...), Age: int = Form(...), hypertension: str = Form(...), heart: str = Form(...), married: str = Form(...), work: str = Form(...), res: str = Form(...), glu: float = Form(...), bmi: float = Form(...), som: str = Form(...) ): # 转换为Health模型实例 data = Health( gender=gender, Age=Age, hypertension=hypertension, heart=heart, married=married, work=work, res=res, glu=glu, bmi=bmi ) data_dict = data.dict() print(data_dict) # 返回渲染后的页面,携带数据 return templates.TemplateResponse('index.html', {'request': request, 'Age': data_dict['Age']})
补充修改:表单中的smoking status字段名是som,需在Health.py中新增对应字段:
from pydantic import BaseModel class Health(BaseModel): gender: str Age: int hypertension: str heart: str married: str work: str res: str glu: float bmi: float som: str # 新增字段对应表单的smoking status
方案二:用Depends简化表单到模型的转换
如果不想逐个定义Form字段,可以自定义依赖函数统一处理:
在main.py中添加依赖函数:
from fastapi import Depends, Form def form_to_health( gender: str = Form(...), Age: int = Form(...), hypertension: str = Form(...), heart: str = Form(...), married: str = Form(...), work: str = Form(...), res: str = Form(...), glu: float = Form(...), bmi: float = Form(...), som: str = Form(...) ) -> Health: return Health( gender=gender, Age=Age, hypertension=hypertension, heart=heart, married=married, work=work, res=res, glu=glu, bmi=bmi, som=som )
修改/predict接口:
@app.post('/predict', response_class=HTMLResponse) def predict(data: Health = Depends(form_to_health), request: Request = Request(...)): data_dict = data.dict() print(data_dict) return templates.TemplateResponse('index.html', {'request': request, 'Age': data_dict['Age']})
额外修复点
HTML中glu和bmi的输入类型错误,将type="type"改为支持小数的数字输入:
<input type="number" step="0.1" name="glu" placeholder="90.8" id="glu"> <input type="number" step="0.1" name="bmi" placeholder="30.1" id="bmi">
内容的提问来源于stack exchange,提问作者PRITAM BHAKTA
相关产品推荐
相关产品推荐

