Cuerpo - Modelos Anidados¶
🌐 Traducción por IA y humanos
Esta traducción fue hecha por IA guiada por humanos. 🤝
Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖
Puedes mejorar esta traducciónayudándonos a guiar mejor al LLM de IA.
ConFastAPI, puedes definir, validar, documentar y usar modelos anidados de manera arbitraria (gracias a Pydantic).
Campos de lista¶
Puedes definir un atributo como un subtipo. Por ejemplo, unalist en Python:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:list=[]@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsEsto hará quetags sea una lista, aunque no declare el tipo de los elementos de la lista.
Campos de lista con parámetro de tipo¶
Pero Python tiene una forma específica de declarar listas con tipos internos, o "parámetros de tipo":
Declarar unalist con un parámetro de tipo¶
Para declarar tipos que tienen parámetros de tipo (tipos internos), comolist,dict,tuple,pasa el/los tipo(s) interno(s) como "parámetros de tipo" usando corchetes:[ y]
my_list:list[str]Eso es toda la sintaxis estándar de Python para declaraciones de tipo.
Usa esa misma sintaxis estándar para atributos de modelos con tipos internos.
Así, en nuestro ejemplo, podemos hacer quetags sea específicamente una "lista de strings":
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:list[str]=[]@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsTipos de conjunto¶
Pero luego pensamos en ello, y nos damos cuenta de que los tags no deberían repetirse, probablemente serían strings únicos.
Y Python tiene un tipo de datos especial para conjuntos de elementos únicos, elset.
Entonces podemos declarartags como un conjunto de strings:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsCon esto, incluso si recibes un request con datos duplicados, se convertirá en un conjunto de elementos únicos.
Y siempre que emitas esos datos, incluso si la fuente tenía duplicados, se emitirá como un conjunto de elementos únicos.
Y también se anotará/documentará en consecuencia.
Modelos Anidados¶
Cada atributo de un modelo Pydantic tiene un tipo.
Pero ese tipo puede ser en sí mismo otro modelo Pydantic.
Así que, puedes declarar "objetos" JSON anidados profundamente con nombres de atributos específicos, tipos y validaciones.
Todo eso, de manera arbitraria.
Definir un submodelo¶
Por ejemplo, podemos definir un modeloImage:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classImage(BaseModel):url:strname:strclassItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()image:Image|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsUsar el submodelo como tipo¶
Y luego podemos usarlo como el tipo de un atributo:
fromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classImage(BaseModel):url:strname:strclassItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()image:Image|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsEsto significaría queFastAPI esperaría un cuerpo similar a:
{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2,"tags":["rock","metal","bar"],"image":{"url":"http://example.com/baz.jpg","name":"The Foo live"}}Nuevamente, haciendo solo esa declaración, conFastAPI obtienes:
- Soporte de editor (autocompletado, etc.), incluso para modelos anidados
- Conversión de datos
- Validación de datos
- Documentación automática
Tipos especiales y validación¶
Además de tipos singulares normales comostr,int,float, etc., puedes usar tipos singulares más complejos que heredan destr.
Para ver todas las opciones que tienes, revisa elOverview de Tipos de Pydantic. Verás algunos ejemplos en el siguiente capítulo.
Por ejemplo, como en el modeloImage tenemos un campourl, podemos declararlo como una instance deHttpUrl de Pydantic en lugar de unstr:
fromfastapiimportFastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classImage(BaseModel):url:HttpUrlname:strclassItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()image:Image|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsEl string será verificado para ser una URL válida, y documentado en JSON Schema / OpenAPI como tal.
Atributos con listas de submodelos¶
También puedes usar modelos Pydantic como subtipos delist,set, etc.:
fromfastapiimportFastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classImage(BaseModel):url:HttpUrlname:strclassItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()images:list[Image]|None=None@app.put("/items/{item_id}")asyncdefupdate_item(item_id:int,item:Item):results={"item_id":item_id,"item":item}returnresultsEsto esperará (convertirá, validará, documentará, etc.) un cuerpo JSON como:
{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2,"tags":["rock","metal","bar"],"images":[{"url":"http://example.com/baz.jpg","name":"The Foo live"},{"url":"http://example.com/dave.jpg","name":"The Baz"}]}Información
Nota cómo la claveimages ahora tiene una lista de objetos de imagen.
Modelos anidados profundamente¶
Puedes definir modelos anidados tan profundamente como desees:
fromfastapiimportFastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classImage(BaseModel):url:HttpUrlname:strclassItem(BaseModel):name:strdescription:str|None=Noneprice:floattax:float|None=Nonetags:set[str]=set()images:list[Image]|None=NoneclassOffer(BaseModel):name:strdescription:str|None=Noneprice:floatitems:list[Item]@app.post("/offers/")asyncdefcreate_offer(offer:Offer):returnofferInformación
Observa cómoOffer tiene una lista deItems, que a su vez tienen una lista opcional deImages
Cuerpos de listas puras¶
Si el valor superior del cuerpo JSON que esperas es unarray JSON (unalist en Python), puedes declarar el tipo en el parámetro de la función, al igual que en los modelos Pydantic:
images:list[Image]como en:
fromfastapiimportFastAPIfrompydanticimportBaseModel,HttpUrlapp=FastAPI()classImage(BaseModel):url:HttpUrlname:str@app.post("/images/multiple/")asyncdefcreate_multiple_images(images:list[Image]):returnimagesSoporte de editor en todas partes¶
Y obtienes soporte de editor en todas partes.
Incluso para elementos dentro de listas:

No podrías obtener este tipo de soporte de editor si estuvieras trabajando directamente condict en lugar de modelos Pydantic.
Pero tampoco tienes que preocuparte por ellos, losdicts entrantes se convierten automáticamente y tu salida se convierte automáticamente a JSON también.
Cuerpos dedicts arbitrarios¶
También puedes declarar un cuerpo como undict con claves de algún tipo y valores de algún otro tipo.
De esta manera, no tienes que saber de antemano cuáles son los nombres válidos de campo/atributo (como sería el caso con modelos Pydantic).
Esto sería útil si deseas recibir claves que aún no conoces.
Otro caso útil es cuando deseas tener claves de otro tipo (por ejemplo,int).
Eso es lo que vamos a ver aquí.
En este caso, aceptarías cualquierdict siempre que tenga clavesint con valoresfloat:
fromfastapiimportFastAPIapp=FastAPI()@app.post("/index-weights/")asyncdefcreate_index_weights(weights:dict[int,float]):returnweightsConsejo
Ten en cuenta que JSON solo admitestr como claves.
Pero Pydantic tiene conversión automática de datos.
Esto significa que, aunque tus clientes de API solo pueden enviar strings como claves, mientras esos strings contengan enteros puros, Pydantic los convertirá y validará.
Y eldict que recibas comoweights tendrá realmente clavesint y valoresfloat.
Resumen¶
ConFastAPI tienes la máxima flexibilidad proporcionada por los modelos Pydantic, manteniendo tu código simple, corto y elegante.
Pero con todos los beneficios:
- Soporte de editor (¡autocompletado en todas partes!)
- Conversión de datos (también conocido como parsing/serialización)
- Validación de datos
- Documentación del esquema
- Documentación automática







