DRF - Views на основе классов
Django rest framework - Class based views
Мы также можем написать наши views API, используя views на основе классов. Как мы увидим, это мощный шаблон, который позволяет нам повторно использовать обычные функции и помогает нам сохранять принцип DRY.
Перепишем наш API с использованием views на основе классов
Мы начнем с переписывания корневого представления как представления на основе классов. Все это включает в себя небольшой рефакторинг views.py.
from snippets.models import Snippet from snippets.serializers import SnippetSerializer from django.http import Http404 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class SnippetList(APIView): """ Показать все сниппеты или создать новый. """ def get(self, request, format=None): snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return Response(serializer.data) def post(self, request, format=None): serializer = SnippetSerializer(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)
Это довольно похоже на предыдущий случай, но мы получили лучшее разделение между методами HTTP. Нам также нужно обновить views Snippet в views.py.
class SnippetDetail(APIView): """ Получить, обновить или удалить сниппет. """ def get_object(self, pk): try: return Snippet.objects.get(pk=pk) except Snippet.DoesNotExist: raise Http404 def get(self, request, pk, format=None): snippet = self.get_object(pk) serializer = SnippetSerializer(snippet) return Response(serializer.data) def put(self, request, pk, format=None): snippet = self.get_object(pk) serializer = SnippetSerializer(snippet, 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, format=None): snippet = self.get_object(pk) snippet.delete() return Response(status=status.HTTP_204_NO_CONTENT)
Выглядит хорошо. Опять же, это все еще очень похоже на функциональное представление.
Нам также нужно будет немного реорганизовать наш snippets/urls.py:
from django.urls import path from rest_framework.urlpatterns import format_suffix_patterns from snippets import views urlpatterns = [ path('snippets/', views.SnippetList.as_view()), path('snippets/<int:pk>/', views.SnippetDetail.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
Если вы запустите сервер разработки, все должно работать так же, как и раньше.
Использование миксинов
Одним из главных преимуществ использования views на основе классов является то, что он позволяет нам легко составлять многократно используемые фрагменты поведения.
Операции создания / извлечения / обновления / удаления, которые мы использовали до сих пор, будут очень похожи для любых представлений API на основе модели. Эти кусочки общего поведения реализованы в смешанных классах инфраструктуры REST. Давайте посмотрим, как мы можем составить представления с помощью классов mixin.
Вот снова наш модуль views.py:
from snippets.models import Snippet from snippets.serializers import SnippetSerializer from rest_framework import mixins from rest_framework import generics class SnippetList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = Snippet.objects.all() serializer_class = SnippetSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
Давайте остановимся на минутку, чтобы выяснить, что именно здесь происходит.
Мы создаем наше views, используя GenericAPIView, и добавляем в ListModelMixin и CreateModelMixin. Базовый класс обеспечивает основные возможности, а классы mixin предоставляют функции .list () и .create (). Затем мы явно привязываем методы get и post к соответствующим функциям. Пока все достаточно просто.
class SnippetDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = Snippet.objects.all() serializer_class = SnippetSerializer def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
Ситуация аналогичная. Мы снова используем класс GenericAPIView для обеспечения основных возможностей и добавляем миксины для предоставления функций .retrieve (), .update () и .destroy ().
Использование generic (общих представлений)
Используя mixin, мы переписали views так, чтобы использовать немного меньше кода, чем раньше, но мы можем пойти еще дальше.
Платформа REST предоставляет набор уже смешанных универсальных представлений, которые мы можем использовать, чтобы еще больше урезать наш модуль views.py.
from snippets.models import Snippet from snippets.serializers import SnippetSerializer from rest_framework import generics class SnippetList(generics.ListCreateAPIView): queryset = Snippet.objects.all() serializer_class = SnippetSerializer class SnippetDetail(generics.RetrieveUpdateDestroyAPIView): queryset = Snippet.objects.all() serializer_class = SnippetSerializer
Вау, это довольно лаконично. Мы получили огромное количество функционала, и наш код выглядит хорошо и чисто.
Далее мы перейдем к четвертой части, где мы рассмотрим, как мы можем работать с аутентификацией и разрешениями для нашего API.