GUIA INTERMEDIÁRIO de Aplicação de API com Django Rest Framework
"Simplifique o desenvolvimento de APIs no Django Rest Framework com um CRUD genérico, aprenda a personalizar ViewSets, lidar com relações e implementar paginação - tudo de forma clean e eficiente!"
Para realizar esse passo a passo, é importante ter realizado o método básico antes... Se ainda não fez, clique aqui
Criando CRUD genérico com Django Rest Framework:
A melhoria de inserção de códigos é feita para evitar a repetição da estrutura no momento de adicionar as funções CRUD.
Para substituir todas as funções criadas no views.py utiliza-se:
from rest_framework import generics
from .models import Curso, Avaliacao
from .serializers import CursoSerializer, AvaliacaoSerializer
class CursosAPIView(generics.ListCreateAPIView):
queryset = Curso.objects.all()
serializer_class = CursoSerializer
class CursoAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Curso.objects.all()
serializer_class = CursoSerializer
Assim como no Django avançado existe o Class Based View o Django Rest também conta com melhorias de otimização de código.
OBS: Repita o mesmo esquema para Avaliação
O ListCreate indicado em genérico indica que é possível listar e criar os métodos, ou seja, as funções GET e POST já estão ativas.
No queryset todos os objetos estão sendo passados, através do objects.all() e o serializer_class informa qual a classe vai sofrer serialização.
Agora além de manter o módulo raw de registro, também possui o formulário (HTML Form).
Atualizando e Deletando os dados da API
A única mudança na estrutura do código é a adição de RetrieveUpdateDestroyAPIView essa indicação na construção da classe ativa os elementos de CRUD de Update e Delete dos dados de uma API.
class CursoAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Curso.objects.all()
serializer_class = CursoSerializer
OBS. O nome das classes de criação e de deleção precisa ser diferente também (sugestão: usar um no plural).
Dessa forma, o arquivo de rotas (urls.py) também precisa ser atualizado.
urlpatterns = [
path('cursos/', CursosAPIView.as_view(), name='cursos'),
path('cursos/<int:pk>/', CursoAPIView.as_view(), name='curso'),
path('cursos/<int:curso_pk>/avaliacoes/', AvaliacoesAPIView.as_view(), name='curso_avaliacoes'),
path('cursos/<int:curso_pk>/avaliacoes/<int:avaliacao_pk>/', AvaliacaoAPIView.as_view(), name='curso_avaliacao'),
]
Na rota do elemento CRUD de deleção é adicionado o primary key, que é uma ID, através de <int:pk>.
Sobrescrevendo os métodos genéricos
Trata-se de formas de sobrescrever os métodos para mudar o comportamento das funções da API.
O objetivo é criar uma rota para associar duas APIs que são complementares… Ou seja, o curso e suas respectivas avaliações.
urlpatterns = [
path('cursos/', CursosAPIView.as_view(), name='cursos'),
path('cursos/<int:pk>/', CursoAPIView.as_view(), name='curso'),
path('cursos/<int:curso_pk>/avaliacoes/', AvaliacoesAPIView.as_view(), name='curso_avaliacoes'),
path('cursos/<int:curso_pk>/avaliacoes/<int:avaliacao_pk>/', AvaliacaoAPIView.as_view(), name='curso_avaliacao'),
path('avaliacoes/', AvaliacoesAPIView.as_view(), name='avaliacoes'),
path('avaliacoes/<int:avaliacao_pk>/', AvaliacaoAPIView.as_view(), name='avaliacao')
]
O elemento <int:curso_pk> indica que a ID extraída é do curso. Assim como, o elemento <int:avaliacao_pk> indica que a ID extraída é da avaliação.
Dessa forma a url gerada vai numerar a ID do curso seguida da ID da avaliação.
EX. api/v1/cursos/3/2 Isso significa que estamos observando a 2º avaliação do curso de ID 3.
Com as rotas alteradas o arquivo views.py também precisa sofrer alterações:
class AvaliacoesAPIView(generics.ListCreateAPIView):
queryset = Avaliacao.objects.all()
serializer_class = AvaliacaoSerializer
def get_queryset(self):
if self.kwargs.get('curso_pk'):
return self.queryset.filter(curso_id=self.kwargs.get('curso_pk'))
return self.queryset.all()
O self.kwargs.get vai pegar os valores das pk (urls.py), e se tiver esse valor, retorna o queryset das avaliações filtradas para aquele curso. Caso não tenha, retorna todas as avaliações.
Cursos representa uma coleção, mas a avaliação é individual. Portanto, a função para sobrescrever tem que ser o get_object() para tratar do objeto (avaliação) de forma individual.
class AvaliacaoAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Avaliacao.objects.all()
serializer_class = AvaliacaoSerializer
def get_object(self):
if self.kwargs.get('curso_pk'):
return get_object_or_404(self.get_queryset(), curso_id=self.kwargs.get('curso_pk'), pk=self.kwargs.get('avaliacao_pk'))
return get_object_or_404(self.get_queryset(), pk=self.kwargs.get('avaliacao_pk'))
No tratamento do objeto individual a função get_object_or_404 vai buscar o objeto através do (‘curso_pk’) se positivo vai buscar as ID das avaliações. Ou automaticamente vai exibir o erro de 404 error caso não encontre ou haja erro de solicitação de dados.
Utilizando ViewSets e Routers:
O objetivo dos ViewSets e Router é diminuir a poluição visual dos endpoints, assim como facilitar na construção da estrutura da API.
É muito utilizado nas melhorias e no versionamento das API, ou seja, manter a antiga funcionando e criar uma atualizada contendo melhorias que não estão presentes na versão anterior.
OBS. Por isso a importância de indicar a versão (v1) na url de acesso da API.
O ViewSets e Routers é uma melhoria que serve para automatizar a criação de endpoints nas API’s.
O ViewSet consiste em agrupar toda a lógica de um determinado recurso em apenas uma classe,
Contextualizando:
from rest_framework import viewsets no arquivo views.py
class CursoViewSet(viewsets.ModelViewSet):
queryset = Curso.objects.all()
serializer_class = CursoSerializer
class AvaliacaoViewSet(viewsets.ModelViewSet):
queryset = Avaliacao.objects.all()
serializer_class = AvaliacaoSerializer
Essa estrutura de dados faz a mesma coisa que aquela sequencia de dados separadas de curso e avaliação construídas no CRUD anteriormente.
No arquivo url.py da aplicação cursos:
from rest_framework.routers import SimpleRouter
from django.urls import path
from rest_framework.routers import SimpleRouter
from .views import (
CursoAPIView,
CursosAPIView,
AvaliacaoAPIView,
AvaliacoesAPIView,
CursoViewSet,
AvaliacaoViewSet)
router = SimpleRouter()
router.register('cursos', CursoViewSet)
router.register('avaliacoes', AvaliacaoViewSet)
Note que a todo momento você está modificando o arquivo urls.py da sua aplicação... Agora...
No arquivo urls.py do projeto:
from django.contrib import admin
from django.urls import path, include
from cursos.urls import router
urlpatterns = [
path('api/v1/', include('cursos.urls')),
path('api/v2/', include(router.urls)),
path('admin/', admin.site.urls),
path('auth/', include('rest_framework.urls')),
]
Ou seja, não há necessidade de construção manual das rotas. O router cria essas rotas de forma automatizada.
OBS: Entretanto usando esse método a rota conjunta não irá funcionar. Porque o SimpleRouter só gera o CRUD para um único model.
Até esse ponto você já utilizou 3 métodos de aplicação de API com Django... O Básico, o CRUD e o Simple Router :)
Até breve!