问题描述
我正在尝试从html表单提交数据,并使用pydantic模型对其进行验证.
使用此代码
I am trying to submit data from html forms and on the validate it with pydantic model.
Using this code
from fastapi import FastAPI, Form
from pydantic import BaseModel
from starlette.responses import HTMLResponse
app = FastAPI()
@app.get("/form", response_class=HTMLResponse)
def form_get():
return '''<form method="post">
<input type="text" name="no" value="1"/>
<input type="text" name="nm" value="abcd"/>
<input type="submit"/>
</form>'''
class SimpleModel(BaseModel):
no: int
nm: str = ""
@app.post("/form", response_model=SimpleModel)
def form_post(form_data: SimpleModel = Form(...)):
return form_data
我怎么会得到http状态为422
不可处理的实体
How ever I get the error with http status 422
Unprocessable Entity
等效的curl命令(由firfox生成)是
Equivalent curl command (generated by firfox) is
此处请求正文包含no=1&nm=abcd
我在做什么错了?
推荐答案
我找到了一个解决方案,可以帮助我们将FastAPI形式也用作pydantic :)
我的代码:
I found a solution which can help us to use FastAPI forms as pydantic as well :)
My code:
class AnyForm(BaseModel):
any_param: str
any_other_param: int = 1
@classmethod
def as_form(
cls,
any_param: str = Form(...),
any_other_param: int = Form(1)
) -> AnyForm:
return cls(any_param=any_param, any_other_param=any_other_param)
@router.post('')
async def any_view(form_data: AnyForm = Depends(AnyForm.as_form)):
...
它像往常一样大张旗鼓地显示
我认为,它可以写得更通用,也许我会返回并编辑答案.
It's showed in the swagger as usual form
I think, it can be written more generic, maybe I will return and edit the answer.
[更新]
我已经把它写成装饰器了
I've written it more generic as a decorator
import inspect
from typing import Type
from fastapi import Form, UploadFile, File
from pydantic import BaseModel
def as_form(cls: Type[BaseModel]):
defaults = cls.__field_defaults__
new_parameters = []
for key, value in cls.__annotations__.items():
default_value = defaults.get(key)
if value == UploadFile:
new_parameters.append(
inspect.Parameter(
key,
inspect._POSITIONAL_ONLY,
default=File(default_value),
annotation=value,
)
)
continue
if default_value is not None:
new_parameters.append(
inspect.Parameter(
key,
inspect._POSITIONAL_ONLY,
default=Form(default_value),
annotation=value,
)
)
else:
new_parameters.append(
inspect.Parameter(
key, inspect._POSITIONAL_ONLY, default=Form(...), annotation=value
)
)
def as_form_func(**data):
return cls(**data)
sig = inspect.signature(as_form_func)
sig = sig.replace(parameters=new_parameters)
as_form_func.__signature__ = sig
cls.as_form = as_form_func
return cls
用法看起来像
class Test1(BaseModel):
a: str
b: int
@as_form
class Test(BaseModel):
param: str
test: List[Test1]
test1: Test1
b: int = 1
a: str = '2342'
@router.post('/me', response_model=Test)
async def me(request: Request, form: Test = Depends(Test.as_form)):
return form
这篇关于fastapi表单数据与pytantic模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!