O problema N+1 aparece quando uma lista faz uma consulta inicial e depois uma consulta por item ao acessar relações. Django oferece carregamento antecipado com estratégias diferentes para relações únicas e coleções.

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 e é adequado a ForeignKey e OneToOne. prefetch_related() executa consultas separadas e combina objetos em Python, funcionando com coleções. Prefetch permite filtrar, ordenar e encadear o queryset relacionado.

Boas práticas

Meça o número de consultas em testes e examine o plano antes de otimizar. Não prefetch relações que a resposta não usa, pois isso aumenta memória e transferência. Em paginação, aplique o carregamento ao queryset paginado e evite acessar novamente uma relação com filtro diferente, o que ignora o cache pré-carregado.

Comece pelo guia de Django. Para APIs com serializers, veja Django REST Framework.

A documentação oficial de QuerySet do Django, consultada em 22 de julho de 2026, detalha a API e seus limites.