Validación de Datos y Esquemas con Pydantic
En el desarrollo de software moderno y arquitecturas web (como FastAPI), garantizar que los datos externos (JSON de APIs, formularios, variables de entorno) cumplan con un esquema estricto y seguro es esencial.
Pydantic es la librería líder de Python para validación y serialización de datos basada en anotaciones de tipo nativas de Python. Su núcleo (en Pydantic v2) está programado en Rust, lo que le otorga un rendimiento extraordinario.
1. Modelos Básicos con BaseModel #
Para definir un esquema, heredas de BaseModel y declaras los campos con sus tipos esperados:
1from pydantic import BaseModel, EmailStr, Field 2 3class UsuarioEsquema(BaseModel): 4 id_usuario: int 5 nombre: str = Field(min_length=2, max_length=50) 6 email: str 7 edad: int = Field(ge=18, le=120) # Mayor o igual a 18, menor o igual a 120 8 es_activo: bool = True 9 10# Creación a partir de un diccionario no validado (ej. JSON entrante) 11datos_crudos = { 12 "id_usuario": "101", # Pydantic coacciona de forma segura '101' a int 101 13 "nombre": "Carlos Gómez", 14 "email": "carlos@example.com", 15 "edad": 34, 16} 17 18usuario = UsuarioEsquema(**datos_crudos) 19print(usuario) 20print(f"Tipo de id_usuario: {type(usuario.id_usuario)}")Salida de consola id_usuario=101 nombre='Carlos Gómez' email='carlos@example.com' edad=34 es_activo=True Tipo de id_usuario: <class 'int'>
2. Captura de Errores de Validación (ValidationError) #
Si los datos recibidos no cumplen con las reglas, Pydantic genera un informe de errores detallado:
1from pydantic import ValidationError 2 3datos_invalidos = { 4 "id_usuario": "no_es_un_numero", 5 "nombre": "A", # Muy corto 6 "email": "carlos@example.com", 7 "edad": 15, # Menor de 18 8} 9 10try: 11 UsuarioEsquema(**datos_invalidos) 12except ValidationError as e: 13 print("Errores detectados:") 14 for error in e.errors(): 15 print(f" - Campo '{error['loc'][0]}': {error['msg']}")
3. Validadores Personalizados con @field_validator #
Puedes añadir reglas de negocio personalizadas a cualquier campo:
1from pydantic import BaseModel, field_validator 2 3class RegistroPago(BaseModel): 4 monto: float 5 moneda: str 6 7 @field_validator("moneda") 8 @classmethod 9 def validar_moneda(cls, valor: str) -> str: 10 monedas_permitidas = {"EUR", "USD", "GBP"} 11 valor_upper = valor.upper() 12 if valor_upper not in monedas_permitidas: 13 raise ValueError(f"Moneda no soportada. Permitidas: {monedas_permitidas}") 14 return valor_upper 15 16pago = RegistroPago(monto=49.99, moneda="eur") 17print(pago.moneda) # Convertido automáticamente a mayúsculasSalida de consola EUR
4. Serialización y Conversión a Diccionarios/JSON #
Pydantic permite exportar instancias fácilmente con .model_dump() (a diccionario) o .model_dump_json() (a JSON formateado):
1# Convertir a diccionario 2dict_data = usuario.model_dump() 3 4# Convertir a cadena JSON 5json_data = usuario.model_dump_json(indent=2) 6print(json_data)
5. Diferencia entre @dataclass y Pydantic BaseModel #
| Característica | @dataclass (Módulo estándar) | Pydantic BaseModel |
|---|---|---|
| Objetivo | Reducir boilerplate y almacenar datos en memoria. | Validación rigurosa de entradas externas, coacción y esquemas. |
| Dependencia | Integrada en la biblioteca estándar de Python. | Librería externa (pip install pydantic). |
| Rendimiento de validación | No valida tipos en runtime (a menos que se programe). | Validación estricta y ultra rápida con motor en Rust. |
| Ecosistema | Uso general en lógica interna. | Integración nativa con FastAPI, SQLModel e IA. |
Resumen del tema
Conceptos clave #
BaseModel: clase base de Pydantic que realiza parseo, coacción de tipos y validación exhaustiva al instanciar.Field(): añade restricciones adicionales (min_length,ge,le,regex, descripciones).@field_validator: decorador para definir reglas de negocio y transformaciones personalizadas sobre campos.- Serialización:
.model_dump()(a dict) y.model_dump_json()(a JSON nativo). - Integración: componente central de frameworks modernos como FastAPI para validar payloads HTTP y generar esquemas OpenAPI.
Qué debes recordar #
Usa Pydantic BaseModel para validar y transformar cualquier dato que entre a tu aplicación desde el exterior (APIs, archivos, configuración), y @dataclass para estructuras de datos internas del dominio.