The N+1 problem occurs when a list executes one initial query and then one additional query per item as relationships are accessed. Django offers different eager-loading strategies for single relations and collections.

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() uses SQL joins and suits ForeignKey or OneToOne. prefetch_related() runs separate queries and combines objects in Python, so it supports collections. Prefetch can filter, order, and further optimize the related queryset.

Practical guidance

Measure query counts in tests and inspect plans before optimizing. Do not prefetch relationships the response never uses because that adds memory and transfer costs. With pagination, apply loading to the paginated queryset and avoid accessing the same relationship through a different filter, which bypasses the prefetched cache.

Start with the Django guide. For serializer-heavy APIs, read Django REST Framework.

The official Django QuerySet documentation, accessed July 22, 2026, documents the API and its constraints.