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.