本文介绍了fastapi表单数据与pytantic模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从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模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-27 04:34