Modelos Pydantic de FastAPI
Pydantic es la dependencia principal de FastAPI para la validación y serialización de datos. Te permite definir modelos de datos con anotaciones de tipos estándar de Python, y automáticamente realiza validación de datos, conversión de tipos y generación de documentación.
¿Qué es Pydantic?
Pydantic es una librería de validación de datos de Python. Su idea central es:Definir estructuras de datos con anotaciones de tipos de Python, y Pydantic se encarga automáticamente de la validación y conversión.En FastAPI, Pydantic se usa principalmente para:
| Uso | Descripción |
|---|---|
| Validación del cuerpo de la solicitud | Valida automáticamente si los datos JSON enviados por el cliente cumplen con la definición del modelo. |
| Serialización del cuerpo de la respuesta | Convierte automáticamente los datos del modelo a respuestas JSON. |
| Documentación automática | Los campos, tipos y reglas de validación del modelo aparecen automáticamente en la documentación de la API. |
| Soporte del editor | Los atributos del modelo tienen autocompletado completo en el editor. |
Definir modelos Pydantic
Crea una clase que herede deBaseModely declara los campos usando tipos estándar de Python:
Ejemplo
class Item(BaseModel):
name: str # Obligatorio: nombre del producto
description: str | None = None # Opcional: descripción del producto
price: float # Obligatorio: precio del producto
tax: float | None = None # Opcional: impuesto
Si un campo es obligatorio depende de si tiene un valor predeterminado:
| Campo | Declaración | ¿Es obligatorio? |
|---|---|---|
name | name: str | Obligatorio |
description | description: str | None = None | Opcional |
price | price: float | Obligatorio |
tax | tax: float | None = None | Opcional |
Usar modelos Pydantic
Como cuerpo de la solicitud
El uso más común es declarar el modelo como parámetro de una función de operación de ruta:
Ejemplo
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.post("/items/")
async def create_item(item: Item):
# FastAPI valida automáticamente el cuerpo de la solicitud y, si pasa la validación, lo asigna al parámetro item
return item
Acceder y manipular datos del modelo
Ejemplo
async def create_item(item: Item):
# Acceder a los atributos del modelo
print(item.name) # Acceder directamente a los atributos
print(item.price) # El editor ofrece autocompletado
# Serializar a diccionario
item_dict = item.model_dump()
print(item_dict) # {"name": "Foo", "description": None, "price": 45.2, "tax": None}
# Serializar a cadena JSON
item_json = item.model_dump_json()
print(item_json) # '{"name":"Foo","description":null,"price":45.2,"tax":null}'
return item_dict
Pydantic v2 usa
model_dump()ymodel_dump_json()en lugar dedict()yjson()método. El nuevo método tiene mejor rendimiento (implementado en Rust).
Ejemplo de validación del modelo
Cuando los datos enviados por el cliente no cumplen con la definición del modelo, FastAPI devuelve errores de validación detallados:
Ejemplo
POST /items/
{
"description": "Faltan name y price"
}
# FastAPI devuelve el error de validación
{
"detail": [
{
"type": "missing",
"loc": ["body", "name"],
"msg": "Field required",
"input": {"description": "Faltan name y price"}
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {"description": "Faltan name y price"}
}
]
}
Si se envían datos con tipos incorrectos:
// price 应该是数字,但传了字符串
{
"name": "Foo",
"price": "not a number"
}
// FastAPI 返回的错误
{
"detail": [
{
"type": "float_parsing",
"loc": ["body", "price"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "not a number"
}
]
}
Métodos comunes de Pydantic v2
| Método | v2 (recomendado) | v1 (obsoleto) | Descripción |
|---|---|---|---|
| Serializar a diccionario | item.model_dump() | item.dict() | Convierte el modelo a un diccionario de Python |
| Serializar a JSON | item.model_dump_json() | item.json() | Convierte el modelo a una cadena JSON |
| Crear desde diccionario | Item.model_validate(data) | Item.parse_obj(data) | Crea y valida el modelo desde un diccionario |
| Crear desde JSON | Item.model_validate_json(json_str) | Item.parse_raw(json_str) | Crea el modelo desde una cadena JSON |
| Obtener JSON Schema | Item.model_json_schema() | Item.schema() | Obtiene el JSON Schema del modelo |
Configuración del modelo (model_config)
Pydantic v2 usamodel_configen lugar delConfigclase interna:
Ejemplo
class Item(BaseModel):
name: str
price: float
# Forma de configuración en Pydantic v2
model_config = ConfigDict(
json_schema_extra={ # Mostrar ejemplos en la documentación de la API
"examples": [
{
"name": "Foo",
"price": 35.4
}
]
}
)
En Pydantic v2,
orm_mode = Truese ha cambiado afrom_attributes = True,schema_extrase ha cambiado ajson_schema_extra,allow_population_by_field_namese ha cambiado apopulate_by_name。
Herencia de modelos
Los modelos Pydantic admiten herencia, lo que permite crear fácilmente modelos de entrada y de salida:
Ejemplo
# Modelo base
class UserBase(BaseModel):
username: str # Obligatorio
email: EmailStr # Obligatorio, valida automáticamente el formato del correo
full_name: str | None = None # Opcional
# Modelo de entrada al crear un usuario (incluye contraseña)
class UserCreate(UserBase):
password: str # Obligatorio
# Modelo de salida al devolver información del usuario (no incluye contraseña)
class UserOut(UserBase):
id: int # Generado por el servidor
# Ejemplo de uso
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserCreate):
# La función recibe UserCreate (con contraseña), pero la respuesta usa UserOut (sin contraseña)
# Así la contraseña no aparece en la respuesta de la API
return {"id": 1, **user.model_dump(exclude={"password"})}
Usar modelos de entrada y salida diferentes es una práctica importante para proteger datos sensibles. Nunca devuelvas campos sensibles como contraseñas en las respuestas de la API.
Resumen
Puntos clave de los modelos Pydantic:
- Usa
BaseModelpara definir modelos de datos, declara los campos con tipos estándar de Python - Los campos con valor predeterminado son opcionales; los que no tienen valor predeterminado son obligatorios.
- v2 usa
model_dump()、model_validate()etc., métodos nuevos - Crea diferentes modelos de entrada/salida mediante herencia de modelos para proteger datos sensibles.
- Toda la validación y la documentación son automáticas; solo necesitas declarar los tipos una vez.