Django REST Framework (DRF) é, sem dúvida, uma das bibliotecas mais completas para construir APIs em Python. A curva de aprendizado inicial é suave — em poucas linhas já se tem um CRUD funcional — mas é justamente essa facilidade que esconde uma série de armadilhas de performance e organização que só aparecem quando o projeto cresce. Depois de anos usando DRF em projetos de produção com alto volume de requisições, reunimos aqui técnicas que fazem diferença real no dia a dia de quem já passou da fase básica do framework.
1. Serializers: evite N+1 com select_related e prefetch_related
O erro de performance mais comum em projetos DRF acontece dentro dos serializers aninhados. Ao serializar uma
lista de pedidos que inclui dados do cliente e dos itens relacionados, o DRF fará uma consulta adicional para
cada relação, para cada item da lista — o clássico problema N+1. A solução está na queryset da view, não no
serializer: usar select_related para relações de chave estrangeira (1-para-1 ou N-para-1) e
prefetch_related para relações reversas ou muitos-para-muitos resolve o problema na origem,
reduzindo dezenas de consultas a apenas duas ou três.
class PedidoViewSet(viewsets.ModelViewSet):
queryset = Pedido.objects.select_related('cliente') \
.prefetch_related('itens__produto')
serializer_class = PedidoSerializer
2. SerializerMethodField tem um custo — use com moderação
Campos calculados via SerializerMethodField são convenientes, mas executam uma função Python
para cada instância serializada, fora do contexto do ORM. Em listagens grandes, isso pode se tornar um gargalo
silencioso. Quando o cálculo pode ser feito no banco (via annotate), essa é sempre a opção mais
performática — transfere o trabalho para o banco de dados, que é otimizado para esse tipo de operação em lote.
3. ViewSets customizados além do CRUD padrão
Nem toda ação de negócio se encaixa nos métodos padrão (list, create, retrieve, update, destroy). O decorator
@action permite adicionar endpoints customizados dentro do mesmo ViewSet, mantendo a organização
RESTful sem forçar operações de negócio dentro dos métodos padrão. Por exemplo, uma ação de "cancelar pedido"
pode ser um endpoint próprio, com sua própria lógica de permissão e serializer, sem poluir o método
update genérico.
class PedidoViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['post'])
def cancelar(self, request, pk=None):
pedido = self.get_object()
pedido.cancelar()
return Response({'status': 'cancelado'})
4. Paginação customizada além do padrão
A paginação padrão do DRF (PageNumberPagination) funciona bem para a maioria dos casos, mas projetos com
grandes volumes de dados se beneficiam de CursorPagination, que evita a degradação de performance
característica de paginação por offset em tabelas grandes. Definir isso globalmente nas configurações do
projeto, com override por view quando necessário, mantém consistência sem repetir código.
5. Throttling: proteja sua API de abuso
DRF já inclui classes de throttling prontas para limitar a taxa de requisições por usuário ou por IP, algo essencial para APIs públicas ou endpoints sensíveis, como login e recuperação de senha. Configurar throttling adequadamente evita tanto ataques de força bruta quanto uso excessivo (intencional ou não) que poderia degradar a performance para todos os outros usuários.
Um endpoint sem limite de requisições não é apenas um risco de segurança — é um convite para que um único cliente mal comportado derrube a experiência de todos os outros.
6. Permissions customizadas para regras de negócio complexas
Além das classes de permissão padrão (IsAuthenticated, IsAdminUser), regras de negócio específicas — como "apenas o dono do pedido pode visualizá-lo" — merecem classes de permissão próprias, reutilizáveis entre diferentes views. Isso evita duplicar verificações de autorização espalhadas em múltiplos métodos e centraliza a lógica de acesso em um único lugar, testável isoladamente.
7. Otimize a serialização em massa com bulk operations
Operações de criação ou atualização em lote através do serializer padrão do DRF geram uma query por objeto, o
que é extremamente ineficiente para grandes volumes. Para esses casos, vale a pena implementar lógica
customizada usando bulk_create e bulk_update do Django diretamente, reservando o
serializer apenas para validação de entrada.
8. Versionamento nativo do DRF
O DRF oferece suporte nativo a versionamento via URL, header ou parâmetro de query, sem exigir bibliotecas externas. Configurar isso desde o início do projeto — mesmo que a API ainda tenha apenas uma versão — facilita significativamente a introdução de mudanças de contrato no futuro sem quebrar clientes existentes.
Considerações finais
Django REST Framework é poderoso o suficiente para sustentar APIs de alta complexidade, mas exige que o desenvolvedor vá além dos exemplos básicos da documentação. Otimizar querysets, usar ViewSets customizados com critério, configurar throttling e pensar em paginação e versionamento desde cedo são práticas que separam um projeto que escala de um que precisa ser reescrito. Se sua equipe precisa de suporte para otimizar ou estruturar uma API em Django, a equipe da ASL Software Engineering pode ajudar. Fale com a gente.