De la misma manera que puedes declarar validación y metadatos adicionales en los parámetros de la función de path operation con Query, Path y Body, puedes declarar validación y metadatos dentro de los modelos Pydantic usando Field de Pydantic.
fromtypingimportAnnotatedfromfastapiimportBody,FastAPIfrompydanticimportBaseModel,Fieldapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Field(default=None,title="The description of the item",max_length=300)price:float=Field(gt=0,description="The price must be greater than zero")tax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Annotated[Item,Body(embed=True)]):results={"item_id":item_id,"item":item}returnresults
🤓 Otras versiones y variantes
Consejo
Preferible usar la versión con Annotated si es posible.
fromfastapiimportBody,FastAPIfrompydanticimportBaseModel,Fieldapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Field(default=None,title="The description of the item",max_length=300)price:float=Field(gt=0,description="The price must be greater than zero")tax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item=Body(embed=True)):results={"item_id":item_id,"item":item}returnresults
Aviso
Nota que Field se importa directamente desde pydantic, no desde fastapi como todos los demás (Query, Path, Body, etc).
Luego puedes usar Field con los atributos del modelo:
fromtypingimportAnnotatedfromfastapiimportBody,FastAPIfrompydanticimportBaseModel,Fieldapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Field(default=None,title="The description of the item",max_length=300)price:float=Field(gt=0,description="The price must be greater than zero")tax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Annotated[Item,Body(embed=True)]):results={"item_id":item_id,"item":item}returnresults
🤓 Otras versiones y variantes
Consejo
Preferible usar la versión con Annotated si es posible.
fromfastapiimportBody,FastAPIfrompydanticimportBaseModel,Fieldapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Field(default=None,title="The description of the item",max_length=300)price:float=Field(gt=0,description="The price must be greater than zero")tax:float|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item=Body(embed=True)):results={"item_id":item_id,"item":item}returnresults
Field funciona de la misma manera que Query, Path y Body, tiene todos los mismos parámetros, etc.
Detalles Técnicos
En realidad, Query, Path y otros que verás a continuación crean objetos de subclases de una clase común Param, que a su vez es una subclase de la clase FieldInfo de Pydantic.
Y Field de Pydantic también devuelve una instancia de FieldInfo.
Body también devuelve objetos de una subclase de FieldInfo directamente. Y hay otros que verás más adelante que son subclases de la clase Body.
Recuerda que cuando importas Query, Path y otros desde fastapi, esos son en realidad funciones que devuelven clases especiales.
Consejo
Nota cómo cada atributo del modelo con un tipo, valor por defecto y Field tiene la misma estructura que un parámetro de la función de path operation, con Field en lugar de Path, Query y Body.
Puedes declarar información extra en Field, Query, Body, etc. Y será incluida en el JSON Schema generado.
Aprenderás más sobre añadir información extra más adelante en la docs, cuando aprendas a declarar ejemplos.
Aviso
Las claves extra pasadas a Field también estarán presentes en el esquema OpenAPI resultante para tu aplicación.
Como estas claves pueden no ser necesariamente parte de la especificación OpenAPI, algunas herramientas OpenAPI, por ejemplo el validador OpenAPI, pueden no funcionar con tu esquema generado.