Django REST Framework - HelpingHandPT/COVID19-be GitHub Wiki
Introdução
Os exemplos providenciados nesta página de Wiki terão como por base o seguinte simples modelo:
class Student(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
score = models.DecimalField(max_digits=10,decimal_places=3)
def __str__(self):
return self.id+self.name+self.score
CBVs e FBVs
Através do Django REST Framework podemos criar RESTful APIs através de Class Based Views ou Function Based Views.
Através de CBVs conseguimos criar com três linhas de código todas as operações CRUD de um modelo ou de uma tabela da base de dados. Se quisermos escrever lógica de negócios de uma forma mais customizável, para isso usamos FBVs.
Nota: além da documentação extensiva no site do DRF, existe ainda Classy Django REST Framework que providencia um interface navegável com métodos e atributos para todas as CBVs do DRF.
Serializers
Uma outra funcionalidade oferecida por DRF são Serializers. Estes são simples de criar e úteis quando um pedido REST chega no protocolo HTTP (XML, JSON, CSV, ...), convertendo o conteúdo desses formatos em objetos Python que poderão ser, posteriormente, armazenados na BD (o oposto também se verifica, ou seja, também podem converter objetos Python vindos da BD em JSON, XML, ...).
Exemplo:
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model= Student
fields=['id','name','score']
Se os estudantes pudessem fazer pedidos, teríamos de usar Nested Serializers
Exemplo:
class PedidosSerializer(serializers.ModelSerializer):
class Meta:
model=Pedidos
fields='__all__' #nomenclatura para introduzir todos os campos do modelo
class StudentSerializer(serializers.ModelSerializer):
pedidos = PedidosSerializer(read_only=True,many=True) # many=True significa que um Student pode ter mais do que um pedido
class Meta:
model = Student
fields='__all__'
O modelo Pedidos seria algo semelhante a isto
class Pedidos(models.Model):
title = models.CharField(max_length=20)
description=models.CharField(max_length=10)
student= models.ForeignKey(Student,related_name='students',on_delete=models.CASCADE)
ORM
Outra funcionalidade útil é o Django Object Relational Mapping (ORM) que permite criar através de métodos operações de BD sem escrever qualquer linha de SQL.
Exemplo:
Student.objects.all()
Student.objects.get(pk=pk)
Web Browsable API
Para navegar pelo REST API, o DRF providencia um Browsable API onde poderemos realizar todas as operações HTTP (GET, POST, PUT, ...). É útil para operações CRUD, não substituíndo uma ferramenta como o Postman para certos pedidos.
Paginação
DRF inclui suporte para estilos de Paginação personalizáveis. Isso permite modificar o quão grandes os conjuntos de resultados são divididos em páginas de dados individuais.
Segurança
DRF suporta criação de Autenticação, Autorização e OAuth. Para isso basta apenas configurarmos, ou seja, não precisaremos de muito código para tal.
Componentes
Request
A classe Request
estende o HttpRequest
, adicionando suporte ao processamento de pedidos e autenticação.
Response
A estrutura REST suporta a negociação de conteúdo HTTP, fornecendo uma classe Response
, que permite retornar conteúdo que pode ser renderizado de várias formas, consoante o pedido do cliente.
A classe Response
subclassa SimpleTemplateResponse
do Django. Os objetos Response
são inicializados com dados, que devem consistir em primitivas nativas do Python. A estrutura REST usa a negociação de conteúdo HTTP padrão para determinar como deve renderizar o conteúdo da resposta final.
Status Codes
O conjunto completo de HTTP Status Codes incluídos no módulo de status
está listado na documentação. Este mesmo módulo também inclui um conjunto de funções auxiliares para testar se um Status Code está é de um determinado tipo.
Exemplo:
status.HTTP_201_CREATED
status.HTTP_400_BAD_REQUEST
@api_view e APIView
O decorador @api_view
exibe uma lista de métodos HTTP aos quais view deve responder (este é usado nas FBVs).
Exemplo:
@api_view(['GET','POST'])
def student_list(request):
if request.method =='GET':
students = Student.objects.all()
serializer=StudentSerializer(students,many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = StudentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET','PUT','DELETE'])
def student_detail(request,pk):
try:
student = Student.objects.get(pk=pk)
except Student.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method=='GET':
serializer = StudentSerializer(student)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = StudentSerializer(student,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
student.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
APIView
, por sua vez, é uma classe que todas as CBVs devem extender.
Exemplo:
class StudentList(APIView):
def get(self,request):
students = Student.objects.all()
serializer = StudentSerializer(students,many=True)
return Response(serializer.data)
def post(self,request):
serializer = StudentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
class StudentDetail(APIView):
def get_object(self,pk):
try:
return Student.objects.get(pk=pk)
except Student.DoesNotExist:
raise Http404
def get(self,request,pk):
student = self.get_object(pk)
serializer = StudentSerializer(student)
return Response(serializer.data)
def put(sefl,request,pk):
student=self.get_object(pk)
serializer=StudentSerializer(student,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
def delete(self,request,pk):
student = self.get_object(pk)
student.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
CBVs
Mixins
As classes mixin fornecem as acções que são usadas para fornecer o comportamento básico das vistas. Observemos que as classes mixin fornecem métodos de acção em vez de definir os métodos handler, como .get() e .post(), diretamente. Isso permite uma composição de comportamento mais flexível.
métodos Action | classes Mixin | métodos Handler |
---|---|---|
list() | ListModelMixin | get() |
create() | CreateModelMixin | post() |
retrieve() | RetrieveModelMixin | get() |
update() | UpdateModelMixin | put() |
delete() | DestroyModelMixin | delete() |
Exemplo:
class StudentList(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
queryset = Student.objects.all()
serializer_class= StudentSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class StudentDetail(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,generics.GenericAPIView):
queryset = Student.objects.all()
serializer_class= StudentSerializer
def get(self,request,pk):
return self.retrieve(request,pk)
def put(self,request,pk):
return self.update(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
Generics
Generics fornecidas pela estrutura REST permitem criar rapidamente views da API. Se as generics não atenderem às necessidades da API, podemos usar a classe APIView
ou reutilizar os mixins
e as classes base usadas pelas generics.
Generics |
---|
CreateAPIView |
ListAPIView |
RetrieveAPIView |
DestroyAPIView |
UpdateAPIView |
ListCreateAPIView (operações sem id - coleções de instâncias do modelo) |
RetrieveUpdateAPIView |
RetrieveDestroyAPIView |
RetrieveUpdateDestroyAPIView |
Exemplo:
class StudentList(generics.ListCreateAPIView):
queryset = Student.objects.all()
serializer_class= StudentSerializer`
class StudentDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Student.objects.all()
serializer_class= StudentSerializer
ViewSets
Uma classe ViewSet é simplesmente um tipo de CBV, que não fornece manipuladores de métodos, como .get () ou .post (), e fornece ações como .list () e .create (). Extendendo uma classa a partir de ViewSet precisaremos de providenciar a implementação para list(), create(), retrieve(), update() e delete(). Pos sua vez, com ModelViewSet não precisamos de escrever quase código. Exemplo:
class StudentViewSet(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = StudentSerializer
Com ViewSets não precisamos de configurar os URLs por nós mesmos. Podemos utilizar Routers. Exemplo:
router = DefaultRouter()
router.register('students',views.StudentViewSet)
urlpatterns = [
path('', include(router.urls)),
]