Back-end

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.