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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:22:07