El problema N+1 aparece cuando una lista ejecuta una consulta inicial y luego otra por cada elemento al acceder a relaciones. Django ofrece estrategias distintas de carga anticipada para relaciones únicas y colecciones.

from django.db.models import Prefetch

pedidos = (
    Pedido.objects
    .select_related("cliente")
    .prefetch_related(
        Prefetch(
            "itens",
            queryset=ItemPedido.objects.select_related("produto"),
        )
    )
)

for pedido in pedidos:
    print(pedido.cliente.nome, [i.produto.nome for i in pedido.itens.all()])

select_related() usa JOIN y sirve para ForeignKey y OneToOne. prefetch_related() ejecuta consultas separadas y combina objetos en Python, por lo que admite colecciones. Prefetch permite filtrar, ordenar y optimizar el queryset relacionado.

Buenas prácticas

Mide el número de consultas en pruebas y examina planes antes de optimizar. No precargues relaciones que la respuesta no utiliza, porque aumentan memoria y transferencia. Con paginación, aplica la carga al queryset paginado y evita acceder a la misma relación con otro filtro, que ignora la caché.

Empieza por la guía de Django. Para APIs con serializers, consulta Django REST Framework.

La documentación oficial de QuerySet de Django, consultada el 22 de julio de 2026, detalla la API y sus límites.