O que é Django REST Framework?
O toolkit mais poderoso para criar APIs RESTful com Django. Utilizado por empresas do mundo inteiro para servir dados ao frontend.
O que é o DRF?
O Django REST Framework (DRF) é uma biblioteca que torna simples a criação de APIs Web robustas e flexíveis com Django. Ele fornece uma série de ferramentas para serializar dados, validar entradas, autenticar usuários e documentar sua API automaticamente.
Com DRF você consegue transformar qualquer projeto Django em uma API que pode ser consumida por aplicativos mobile, frontends React/Next.js ou outros serviços. É o padrão da indústria para APIs Python — utilizado pelo Mozilla, Red Hat, Heroku, Eventbrite e inúmeras outras empresas.
Por que usar o DRF?
- Serializers poderosos: converte dados Python/Django para JSON (e vice-versa) com validação automática
- ViewSets e Routers: CRUD completo com pouquíssimo código
- Browsable API: interface web automática para testar sua API no navegador durante desenvolvimento
- Autenticação flexível: suporta Token, Session, OAuth, JWT via simplejwt
- Permissões granulares: controle quem pode fazer o quê na API por endpoint
- Paginação automática: lista grande de dados com paginação nativa
- Filtros e busca: integração com django-filter para filtros poderosos
- Throttling: limite de requisições por usuário para proteger a API
Instalação
pip install djangorestframework
pip install djangorestframework-simplejwt # para JWT
pip install django-filter # para filtros avançados
# No settings.py, adicione à INSTALLED_APPS:
INSTALLED_APPS = [
...
'rest_framework',
'django_filters',
]Serializer — o coração do DRF
O Serializer faz a ponte entre seus models Django e o JSON da API. O ModelSerializer gera automaticamente os campos a partir do model:
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Post, Categoria
User = get_user_model()
class AutorSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'first_name', 'last_name']
class CategoriaSerializer(serializers.ModelSerializer):
class Meta:
model = Categoria
fields = ['id', 'nome', 'slug']
class PostSerializer(serializers.ModelSerializer):
# Nested serializer — autor embutido no JSON de leitura
autor = AutorSerializer(read_only=True)
categoria = CategoriaSerializer(read_only=True)
# Campo de escrita separado para o FK
categoria_id = serializers.PrimaryKeyRelatedField(
queryset=Categoria.objects.all(),
source='categoria',
write_only=True,
required=False,
)
tempo_leitura = serializers.SerializerMethodField()
class Meta:
model = Post
fields = [
'id', 'titulo', 'slug', 'conteudo', 'resumo',
'autor', 'categoria', 'categoria_id',
'publicado_em', 'atualizado_em', 'publicado',
'visualizacoes', 'tempo_leitura',
]
read_only_fields = ['publicado_em', 'atualizado_em', 'visualizacoes', 'autor']
def get_tempo_leitura(self, obj):
palavras = len(obj.conteudo.split())
return max(1, round(palavras / 200))
def validate_slug(self, value):
# Valida unicidade ignorando o próprio objeto em update
qs = Post.objects.filter(slug=value)
if self.instance:
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
raise serializers.ValidationError('Este slug já está em uso.')
return value
def create(self, validated_data):
# Adiciona o autor automaticamente a partir do request
validated_data['autor'] = self.context['request'].user
return super().create(validated_data)ViewSet — CRUD em poucas linhas
Com um ModelViewSet, você tem list, create, retrieve, update e delete automaticamente. Use o decorador @action para endpoints extras:
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAdminUser
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.filter(publicado=True).select_related('autor', 'categoria')
serializer_class = PostSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
# Filtros, busca e ordenação
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['categoria', 'publicado']
search_fields = ['titulo', 'conteudo', 'autor__username']
ordering_fields = ['publicado_em', 'visualizacoes']
ordering = ['-publicado_em']
def get_queryset(self):
# Admins veem todos os posts, usuários normais só os publicados
if self.request.user.is_staff:
return Post.objects.all().select_related('autor', 'categoria')
return Post.objects.filter(publicado=True).select_related('autor', 'categoria')
def get_permissions(self):
# Apenas admins podem deletar
if self.action == 'destroy':
return [IsAdminUser()]
return super().get_permissions()
# Endpoint extra: POST /api/posts/{id}/publicar/
@action(detail=True, methods=['post'], permission_classes=[IsAdminUser])
def publicar(self, request, pk=None):
post = self.get_object()
post.publicado = True
post.save(update_fields=['publicado'])
return Response({'status': 'publicado'}, status=status.HTTP_200_OK)
# Endpoint extra: GET /api/posts/populares/
@action(detail=False, methods=['get'])
def populares(self, request):
posts = self.get_queryset().order_by('-visualizacoes')[:10]
serializer = self.get_serializer(posts, many=True)
return Response(serializer.data)APIView — controle total sobre o endpoint
Para endpoints que não se encaixam no padrão CRUD, use APIView ou o decorador @api_view:
from rest_framework.views import APIView
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
# Com @api_view (simples, para endpoints únicos)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def meu_perfil(request):
serializer = PerfilSerializer(request.user, context={'request': request})
return Response(serializer.data)
# Com APIView (para múltiplos métodos HTTP)
class EstatisticasAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
stats = {
'total_posts': Post.objects.filter(autor=request.user).count(),
'posts_publicados': Post.objects.filter(autor=request.user, publicado=True).count(),
'total_visualizacoes': Post.objects.filter(autor=request.user).aggregate(
total=models.Sum('visualizacoes')
)['total'] or 0,
}
return Response(stats, status=status.HTTP_200_OK)Router — URLs automáticas
O Router gera todas as URLs necessárias para os ViewSets registrados:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import PostViewSet, CategoriaViewSet
router = DefaultRouter()
router.register(r'posts', PostViewSet, basename='post')
router.register(r'categorias', CategoriaViewSet, basename='categoria')
urlpatterns = [
path('api/v1/', include(router.urls)),
path('api/v1/me/', meu_perfil),
path('api/v1/estatisticas/', EstatisticasAPIView.as_view()),
]
# O Router cria automaticamente:
# GET /api/v1/posts/ → lista (list)
# POST /api/v1/posts/ → criar (create)
# GET /api/v1/posts/{id}/ → detalhe (retrieve)
# PUT /api/v1/posts/{id}/ → atualizar completo (update)
# PATCH /api/v1/posts/{id}/ → atualizar parcial (partial_update)
# DELETE /api/v1/posts/{id}/ → deletar (destroy)
# POST /api/v1/posts/{id}/publicar/ → action customizada
# GET /api/v1/posts/populares/ → action customizada (list)Autenticação JWT com simplejwt
O djangorestframework-simplejwt é a biblioteca padrão para autenticação JWT no DRF. Configure as URLs e ajuste os tempos de expiração conforme sua necessidade:
# settings.py
from datetime import timedelta
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day',
},
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'AUTH_HEADER_TYPES': ('Bearer',),
}# urls.py — endpoints de autenticação JWT
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns += [
path('api/auth/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/auth/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/auth/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
# Uso no cliente:
# POST /api/auth/token/ com {"username": "...", "password": "..."}
# → retorna {"access": "...", "refresh": "..."}
# POST /api/auth/token/refresh/ com {"refresh": "..."}
# → retorna novo {"access": "..."}Permissões customizadas
Além das permissões padrão do DRF, você pode criar permissões específicas para o seu negócio:
from rest_framework.permissions import BasePermission, SAFE_METHODS
class EhAutorOuSomenteLeitura(BasePermission):
"""
Permite acesso total ao autor do objeto.
Para outros usuários autenticados, apenas leitura.
"""
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.autor == request.user
class EhAssinante(BasePermission):
"""
Permite acesso apenas a usuários com assinatura ativa.
"""
message = 'Você precisa de uma assinatura ativa para acessar este conteúdo.'
def has_permission(self, request, view):
return (
request.user.is_authenticated
and hasattr(request.user, 'assinatura')
and request.user.assinatura.ativa
)
# Usando no ViewSet:
class PostViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated, EhAutorOuSomenteLeitura]Paginação customizada
Para ter controle total sobre o formato da paginação na resposta JSON:
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class PaginacaoPadrao(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
def get_paginated_response(self, data):
return Response({
'pagination': {
'total': self.page.paginator.count,
'paginas': self.page.paginator.num_pages,
'pagina_atual': self.page.number,
'proxima': self.get_next_link(),
'anterior': self.get_previous_link(),
},
'results': data,
})Perguntas Frequentes
Preciso do Django instalado para usar o DRF?
Sim, o Django REST Framework é uma extensão do Django. Você precisa ter um projeto Django configurado antes de instalar o DRF. O DRF não funciona de forma standalone.
Qual a diferença entre APIView e ViewSet?
APIView é mais manual — você define os métodos GET, POST etc. explicitamente. ViewSet é mais automático, gerando todos os métodos CRUD de uma vez com Router. Para recursos padrão, use ViewSet. Para lógica muito customizada ou endpoints que não seguem o padrão REST, use APIView.
O DRF serve para autenticação com JWT?
O DRF tem autenticação básica e por sessão nativamente. Para JWT, a biblioteca mais usada é o djangorestframework-simplejwt, que se integra perfeitamente ao DRF e é o padrão nos tutoriais do canal.
Como faço paginação com DRF?
O DRF tem suporte nativo a paginação. Basta configurar DEFAULT_PAGINATION_CLASS nas settings. Existem três estilos: PageNumberPagination (/?page=2), LimitOffsetPagination (/?limit=10&offset=20) e CursorPagination (para feeds infinitos).
DRF funciona com frontend React/Vue/Next.js?
Sim! Essa é justamente a arquitetura que ensinamos no canal: backend Django + DRF servindo uma API JSON, e frontend React/Next.js consumindo essa API via fetch ou bibliotecas como axios ou TanStack Query.
Como implementar busca e filtros na API DRF?
O DRF tem integração com django-filter para filtros poderosos. Instale django-filter e configure filter_backends no ViewSet. Você pode adicionar SearchFilter para busca por texto e OrderingFilter para ordenação — tudo configurável por parâmetros de URL.
O que são nested serializers e quando usar?
Nested serializers representam relacionamentos entre models na mesma resposta JSON. Por exemplo, um PostSerializer pode incluir um AutorSerializer embutido. Use para leitura (GET) quando o cliente precisa dos dados relacionados. Para escrita, prefira receber apenas o ID do relacionamento para evitar complexidade.
Como proteger endpoints contra muitas requisições?
O DRF tem throttling (limitação de taxa) nativo. Configure DEFAULT_THROTTLE_CLASSES e DEFAULT_THROTTLE_RATES nas settings. Você pode ter taxas diferentes para usuários autenticados vs anônimos, e também criar throttling por endpoint específico.
Qual a diferença entre authentication e permission no DRF?
Authentication identifica quem é o usuário (JWT, Token, Session). Permission decide se o usuário identificado pode executar a ação (IsAuthenticated, IsAdminUser, permissão customizada). São dois passos distintos na pipeline do DRF.