Pydantic Schema — Validación y serialización de datos

En este capítulo aprenderás Pydantic Schema, entenderás su separación de responsabilidades con el modelo ORM, que es la característica más central de FastAPI.


¿Por qué necesitamos un Schema?

El modelo ORM (models.py) define la estructura de la base de datos, pero no se puede usar directamente para la validación de solicitudes/respuestas de la API.

Razón: el modelo ORM contiene lógica específica de la base de datos (como relationship), y no se desea exponer todos los campos a la API.

Pydantic SchemaEs una clase de datos pura, dedicada a la validación y serialización de entrada/salida de la API.

La relación entre estos tres:

客户端 → [Pydantic Schema 校验] → 路由函数 → [ORM 模型] → 数据库
客户端 ← [Pydantic Schema 序列化] ← 路由函数 ← [ORM 模型] ← 数据库

Fundamentos de Pydantic Schema

Pydantic V2 es el motor de datos de FastAPI, define estructuras de datos mediante sugerencias de tipo.

Ejemplo

from pydantic import BaseModel, ConfigDict

class ItemCreate(BaseModel):
    """Crear el Schema de la solicitud"""
    name: str
    price: float                       # Validar tipos automáticamente
    is_offer: bool = False             # Con valor predeterminado (campo opcional)

class ItemResponse(BaseModel):
    """Schema de respuesta"""
    id: int
    name: str
    price: float

    # Sintaxis V2: activar el modo ORM, permite convertir directamente desde objetos ORM
    model_config = ConfigDict(from_attributes=True)

Definir el Schema del blog

Ejemplo

# Ruta del archivo: schemas.py
from pydantic import BaseModel, ConfigDict
from datetime import datetime
from typing import Optional

# ====== Category Schema ======
class CategoryBase(BaseModel):
    name: str
    slug: str

class CategoryResponse(CategoryBase):
    id: int
    model_config = ConfigDict(from_attributes=True)

# ====== Post Schema ======
class PostBase(BaseModel):
    title: str
    slug: str
    summary: Optional[str] = None      # Optional = puede ser None
    content: str
    category_id: int

class PostCreate(PostBase):
    """Schema del cuerpo de la solicitud al crear un artículo"""
    pass                               # Hereda directamente de PostBase, campos idénticos

class PostUpdate(BaseModel):
    """Actualizar artículo (todos los campos opcionales)"""
    title: Optional[str] = None
    slug: Optional[str] = None
    summary: Optional[str] = None
    content: Optional[str] = None
    category_id: Optional[int] = None

class PostResponse(PostBase):
    """Schema de respuesta devuelto al cliente"""
    id: int
    created_at: datetime
    updated_at: datetime
    category: CategoryResponse         # Schema anidado: devolver información de la categoría

    model_config = ConfigDict(from_attributes=True)
    # from_attributes=True le dice a Pydantic: este Schema se puede crear desde un objeto ORM

En Pydantic V2,model_config = ConfigDict(from_attributes=True)reemplaza al de V1class Config: orm_mode = True. Esta configuración te permite construir un Pydantic Schema directamente desde un objeto SQLAlchemy ORM:PostResponse.model_validate(post_orm_obj)。


Usar Schema en las rutas

Ejemplo

# Ruta del archivo: routers/posts.py (ejemplo de creación de una ruta POST)
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from database import get_db
from models import Post
from schemas import PostCreate, PostResponse

router = APIRouter(prefix="/posts", tags=["Artículo"])

# Después de declarar response_model=PostResponse:
# 1. FastAPI convierte automáticamente el objeto ORM a Schema (serialización)
# 2. El documento de la API muestra automáticamente la estructura de la respuesta
@router.post("/", response_model=PostResponse, status_code=201)
def create_post(post_data: PostCreate, db: Session = Depends(get_db)):
    """
Crear nuevo artículo
- post_data: cuerpo de la solicitud, FastAPI lo valida automáticamente según el Schema PostCreate
- db: sesión de base de datos inyectada mediante Depends(get_db)
    """

    post = Post(**post_data.model_dump())  # model_dump() convierte el Schema a diccionario
    db.add(post)
    db.commit()
    db.refresh(post)                       # Refrescar, obtener el ID autoincremental de la base de datos
    return post                            # FastAPI serializa automáticamente con PostResponse

response_modelEs una de las características más potentes de FastAPI. Tras declararlo, FastAPI: 1. Filtra automáticamente los campos del objeto ORM que no están declarados en el Schema; 2. Convierte automáticamente tipos como datetime a cadenas JSON; 3. Genera documentación OpenAPI precisa.


Comparación entre modelo ORM y Pydantic Schema

AspectoModelo SQLAlchemy ORMPydantic Schema
Ubicación de definiciónmodels.pyschemas.py
Clase baseBase (DeclarativeBase)BaseModel (Pydantic)
ResponsabilidadDefine la estructura y relaciones de las tablas de la base de datosDefine los formatos de entrada/salida de la API y las reglas de validación
Relación con la base de datosMapea directamente las tablas de la base de datosNo le importa la base de datos, solo el contrato de la API
Declaración de camposColumn(Integer, ...)Sugerencias de tipo de Python: int, str
SerializaciónNo se puede convertir directamente a JSONIncorpora .model_dump() y serialización JSON
Dirección de conversiónORM → Schema:model_validate(obj)Schema → ORM:Model(**schema.model_dump())

Resumen del capítulo

En este capítulo has dominado el Pydantic Schema más central de FastAPI: BaseModel define los Schemas de solicitud/respuesta, from_attributes=True activa el modo ORM, response_model serializa automáticamente los objetos ORM, y el principio de separación de responsabilidades entre Schema y modelo ORM.

Este es el núcleo de la arquitectura impulsada por tipos de FastAPI: primero define la forma de los datos, y las rutas y la documentación se generan automáticamente.

Otras extensiones