Contenido del curso
Parámetros y Validación
CRUD en FastAPI
Arquitectura en FastAPI
Bases de Datos y Consultas
- 13

Relaciones en FastAPI y SQL Model: Creación y Uso Práctico
18:09 min - 14

Relaciones Muchos a Muchos en Bases de Datos con SQLModel
06:39 min - 15

Creación y Suscripción de Planes y Clientes en FastAPI
Viendo ahora - 16

Consultas Avanzadas con SQL Model y Filtrado de Estados en FastAPI
07:20 min - 17

Validación de Emails Únicos en Bases de Datos con Pydantic y FastAPI
07:28 min
Middlewares
Unit Testing
Seguridad y Autenticación
Creación y Suscripción de Planes y Clientes en FastAPI
Resumen
Construir una API que permita crear planes, listar planes y suscribir clientes a esos planes es una tarea fundamental cuando trabajas con modelos de negocio basados en suscripciones. A continuación se explica paso a paso cómo lograrlo usando FastAPI, SQLModel y una base de datos SQLite, cubriendo desde la creación del router hasta la validación de relaciones muchos a muchos.
¿Cómo crear el endpoint para registrar planes?
El primer paso es generar un nuevo archivo dentro de la carpeta routers llamado plans. Dentro de él se importa APIRouter desde FastAPI y se define el router [0:18].
El endpoint de creación utiliza el método POST con el path /plans. Recibe dos parámetros: plan_data de tipo Plan (importado desde los modelos) y la session de base de datos [0:30].
python @router.post("/plans") async def create_plan(plan_data: Plan, session: Session): plan_db = Plan.model_validate(plan_data.model_dump()) session.add(plan_db) session.commit() session.refresh(plan_db) return plan_db
- model_validate recibe un diccionario con todos los campos y valida la data del usuario.
- session.add agrega el objeto a la sesión.
- session.commit ejecuta la transacción en la base de datos.
- session.refresh actualiza la variable en memoria con los datos persistidos, incluyendo el ID generado.
Después de registrar el router en main.py y correr la aplicación, ya es posible probar desde los docs de FastAPI [1:06].
¿Qué hacer cuando la base de datos no refleja los cambios del modelo?
Si al ejecutar el request aparece un error indicando que un campo no existe, significa que el modelo fue modificado pero la base de datos no se regeneró [1:18]. Lo ideal es usar migraciones, pero como alternativa rápida se puede borrar la base de datos y reiniciar la aplicación para que se recreen las tablas con el schema actualizado [1:36].
Para verificar, se puede inspeccionar el schema de la tabla plan directamente en la terminal y confirmar que los nuevos campos ya existen [1:52].
¿Cómo suscribir un customer a un plan específico?
Con los planes creados (por ejemplo, premium con precio 1000 y basic con precio 100), el siguiente objetivo es construir un endpoint que relacione un customer con un plan [2:22].
Este endpoint se coloca en el router de customers porque la URL sigue una ruta anidada: /customers/{customer_id}/plans/{plan_id} [2:40].
python @router.post("/customers/{customer_id}/plans/{plan_id}") async def subscribe_customer_to_plan(customer_id: int, plan_id: int, session: Session): customer_db = session.get(Customer, customer_id) plan_db = session.get(Plan, plan_id)
if not customer_db or not plan_db: raise HTTPException(status_code=404, detail="The customer or plan doesn't exist") customer_plan_db = CustomerPlan(plan_id=plan_db.id, customer_id=customer_db.id) session.add(customer_plan_db) session.commit() session.refresh(customer_plan_db) return customer_plan_db
- Se obtienen ambos objetos con
session.get[2:55]. - Se valida que existan; si alguno no se encuentra, se lanza una HTTPException con código 404 [3:10].
- La relación se crea instanciando
CustomerPlan, el modelo intermedio que requiereplan_idycustomer_id[3:30]. - Sin el
session.refresh, la respuesta aparece vacía porque los datos no se actualizan en memoria [4:10].
¿Cómo listar las suscripciones de un customer?
Para consultar todos los planes a los que un customer está suscrito, se define un endpoint GET en /customers/{customer_id}/plans [4:28].
python @router.get("/customers/{customer_id}/plans") async def list_customer_plans(customer_id: int, session: Session): customer_db = session.get(Customer, customer_id) if not customer_db: raise HTTPException(status_code=404, detail="Customer not found") return customer_db.plans
- Se obtiene el customer por ID.
- Si no existe, se retorna un error 404.
- Si existe, se retornan directamente los planes gracias a la relación definida en el modelo [4:50].
¿Qué reto queda pendiente para practicar?
Con la relación muchos a muchos completamente funcional, un excelente ejercicio es agregar un campo de estado dentro del modelo CustomerPlan y luego modificar el endpoint de listado para filtrar únicamente los planes que estén activos [5:15]. ¿Ya lo intentaste? Comparte tu solución y cuéntanos cómo resolviste el filtrado.