J'essaie de soumettre des données de formulaires HTML et sur le validez-le avec le modèle PYDANTIC.
[.____] Utiliser ce 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
Comment puis-je obtenir l'erreur avec l'état HTTP 422
Entité non-accessoire
{"Détail": [{"loc": ["corps", "form_data"], "msg": "champ requis", "Type": "value_error.missing"}]}
Commande curl équivalente (générée par FIRFOX) est
curl ' http: // localhost: 8001/formulaire ' -H 'Type de contenu: Application/X-www-Form-Urlencodé' --Data 'No = 1 & nm = ABCD'
Ici le corps de la demande contient no=1&nm=abcd
Qu'est-ce que je fais mal?
J'ai trouvé une solution qui peut nous aider à utiliser Fastapi Forms comme Pydantic également :)
[.____] Mon 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)):
...
Il est montré dans la forme de Swagger comme une forme habituelle
[.____] Je pense que cela peut être écrit plus générique, peut-être que je reviendrai et modifierai la réponse.
[ACTUALISÉ]
J'ai écrit plus générique comme un décorateur
import inspect
from typing import Type
from fastapi import Form
from pydantic import BaseModel
from pydantic.fields import ModelField
def as_form(cls: Type[BaseModel]):
new_parameters = []
for field_name, model_field in cls.__fields__.items():
model_field: ModelField # type: ignore
if not model_field.required:
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Form(model_field.default),
annotation=model_field.outer_type_,
)
)
else:
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Form(...),
annotation=model_field.outer_type_,
)
)
async 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 # type: ignore
setattr(cls, 'as_form', as_form_func)
return cls
Et l'utilisation ressemble
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
Si vous envisagez seulement d'abstraire les données de formulaire dans une classe, vous pouvez le faire avec une classe ordinaire
from fastapi import Form, Depends
class AnyForm:
def __init__(self, any_param: str = Form(...), any_other_param: int = Form(1)):
self.any_param = any_param
self.any_other_param = any_other_param
def __str__(self):
return "AnyForm " + str(self.__dict__)
@app.post('/me')
async def me(form: AnyForm = Depends()):
print(form)
return form
Et il peut également être transformé en un modèle pydantic
from uuid import UUID, uuid4
from fastapi import Form, Depends
from pydantic import BaseModel
class AnyForm(BaseModel):
id: UUID
any_param: str
any_other_param: int
def __init__(self, any_param: str = Form(...), any_other_param: int = Form(1)):
id = uuid4()
super().__init__(id, any_param, any_other_param)
@app.post('/me')
async def me(form: AnyForm = Depends()):
print(form)
return form
J'ai mis en place la solution trouvée ici Sause Solution et cela semblait fonctionner
[. ____ ____.] App = fastapi () [.____] [.____] def formulaire_body (CLS): [.____] CLS .__ Signature__ =. Remplacer ( Paramètres = arg.replace (par défaut = formulaire (...)) [ .____] Retourne CLS [.____] [.____] [.____] @form_body Article de classe (Basemodel): [.____] Nom: STR [.____] @ app.post ('/ test', réponse_model = élément) [.____] defoint de défense (item)): Renvoyer l'objet [.____] [.____] [. ____] TC = testclient (app) [.____] [.____] [. ____] r = tc.post ('/ test " , Data = {'Nom': 'Nom', 'Un autre': 'Un autre'}) [.____] [ .]