En pocas palabras
Biblioteca de Python que define modelos con anotaciones de tipos para validar, transformar y serializar datos en ejecución.
Qué problema resuelve
Datos externos con campos ausentes, tipos incorrectos o valores que incumplen restricciones.
Cuándo utilizarlo
APIs, configuración, pipelines y salidas estructuradas de LLM. Ejemplo: validar que un objeto extraído de un documento contiene identificadores y un importe positivo antes de procesarlo.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
Cómo funciona
Los modelos describen tipos y restricciones. Pydantic valida la entrada y produce objetos Python o errores detallados; después puede serializar el resultado y generar JSON Schema para integraciones.
Ejemplo: validar un importe
Con Pydantic 2 instalado:
from pydantic import BaseModel, ConfigDict, PositiveFloat
class Solicitud(BaseModel):
model_config = ConfigDict(strict=True)
identificador: str
importe: PositiveFloat
solicitud = Solicitud.model_validate({
"identificador": "SOL-001",
"importe": 150.0,
})
print(solicitud.model_dump())
Validadores y tipos con restricciones
from datetime import date
from decimal import Decimal
from typing import Annotated, Literal
from pydantic import BaseModel, Field, field_validator, model_validator
Monto = Annotated[Decimal, Field(gt=0, max_digits=14, decimal_places=2)]
class SolicitudCredito(BaseModel):
documento: Annotated[str, Field(pattern=r"^\d{6,10}$")]
pais: Literal["CO", "MX", "PE"]
monto: Monto
plazo_meses: Annotated[int, Field(ge=3, le=60)]
fecha_nacimiento: date
@field_validator("documento")
@classmethod
def sin_ceros_iniciales(cls, v: str) -> str:
return v.lstrip("0")
@model_validator(mode="after")
def mayor_de_edad(self):
edad = (date.today() - self.fecha_nacimiento).days // 365
if edad < 18:
raise ValueError("El solicitante debe ser mayor de edad")
return self
Decimal con max_digits y decimal_places evita los errores de redondeo de float en importes.
Errores estructurados
from pydantic import ValidationError
try:
SolicitudCredito.model_validate(payload)
except ValidationError as e:
for err in e.errors():
print(err["loc"], err["type"], err["msg"])
# ('monto',) greater_than Input should be greater than 0
Cada error indica ubicación, tipo y mensaje, lo que permite devolver respuestas 422 precisas (así lo hace FastAPI).
Configuración con Pydantic Settings
from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Ajustes(BaseSettings):
model_config = SettingsConfigDict(env_prefix="APP_", env_file=".env")
database_url: str
buro_api_key: SecretStr
timeout_segundos: float = 3.0
ajustes = Ajustes() # lee APP_DATABASE_URL, APP_BURO_API_KEY…
SecretStr evita que el valor aparezca en logs o en repr. Si falta una variable obligatoria, la aplicación falla al arrancar en lugar de en la primera petición.
Serialización y JSON Schema
| Método | Uso |
|---|---|
model_dump(mode="json") |
Diccionario serializable (fechas y Decimal como texto) |
model_dump_json(exclude_none=True) |
JSON directamente, rápido |
model_json_schema() |
JSON Schema para OpenAPI, contratos o LLM |
TypeAdapter(list[Modelo]) |
Validar tipos que no son modelos |
El JSON Schema generado es la base de structured output con LLM y de frameworks como Pydantic AI.
Rendimiento
El núcleo de validación (pydantic-core) está escrito en Rust. Para grandes volúmenes, valida directamente desde JSON con model_validate_json (evita el paso intermedio por dict) y reutiliza TypeAdapter en lugar de crearlo en cada llamada.
Criterios de implementación
Define si permites conversiones o exiges tipos estrictos. Para cantidades monetarias reales, evalúa Decimal y reglas de precisión. Comprueba referencias y permisos fuera del esquema: un identificador bien formado puede no existir.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.