Listar clientes con paginación
Objetivos
Vas a responder una lista sin cargar todas las filas y permitir que la persona avance mediante limit y offset acotados.
Concepto
La paginación divide una lista en bloques. limit indica cuántas filas como máximo se devuelven; offset indica cuántas se saltan. Sin límite, un endpoint podría leer cientos o miles de filas en una sola petición. Sin un orden estable, los bloques pueden cambiar de una consulta a otra.
FastAPI valida los parámetros antes de llamar la función. SQLAlchemy añade el límite y el desplazamiento a la consulta. En este ejemplo, customer_id establece un orden reproducible y CustomerPage comunica los valores usados. La paginación no es un filtro de seguridad ni evita compartir información que no debería exponerse: el modelo de respuesta sigue siendo necesario.
Ejemplo
En app/schemas.py, añade un envoltorio para una página debajo de la clase CustomerOut de la lección anterior:
from pydantic import BaseModel
class CustomerPage(BaseModel):
items: list[CustomerOut]
limit: int
offset: intEn app/main.py, registra el endpoint:
from typing import Annotated
from fastapi import Depends, FastAPI, Query
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.database import get_db
from app.models import Customer
from app.schemas import CustomerOut, CustomerPage
@app.get("/customers", response_model=CustomerPage)
def list_customers(
db: Annotated[Session, Depends(get_db)],
limit: Annotated[int, Query(ge=1, le=50)] = 20,
offset: Annotated[int, Query(ge=0, le=10000)] = 0,
) -> CustomerPage:
statement = (
select(Customer)
.order_by(Customer.customer_id)
.limit(limit)
.offset(offset)
)
rows = db.scalars(statement).all()
return CustomerPage(items=rows, limit=limit, offset=offset)Una llamada a /customers?limit=10&offset=20 devuelve hasta diez clientes después de saltar los primeros veinte. le=50 evita pedir una página enorme por accidente. El orden es siempre por customer_id, no por el orden interno del motor.
Práctica guiada
- Prueba una página de 5 registros y una segunda con
offset=5. - Confirma que las claves no se repitan entre las páginas.
- Prueba
limit=0y observa que FastAPI devuelve422sin consultar la base.
Reto
Agrega un filtro opcional active de tipo booleano. Si no se envía, conserva todos los estados; si se envía, compara con la columna Customer.active.
Intenta el reto antes de consultar las pistas.
Quiz
Comprobación
La lista ya tiene límite, orden y desplazamiento. La siguiente lección lleva esos mismos controles a los pagos y agrega filtros que no aceptan SQL libre.