Spec-Zone.ru › Django REST Framework

Урок 3: Виды представлений на основе классов

Мы также можем написать представления API, используя виды представлений на основе классов, а не функций. Как мы увидим, это мощный шаблон, который позволяет нам повторно использовать общую функциональность и помогает нам поддерживать код DRY.

Переработка нашего API с использованием видов представлений на основе классов

Мы начнём с переработки корневого представления как представления на основе класса. Всё это включает в себя небольшую переработку 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):
    """
    List all snippets, or create a new snippet.
    """
    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.py.

class SnippetDetail(APIView):
    """
    Retrieve, update or delete a snippet instance.
    """
    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)

Хорошо, мы закончили. Если вы запустите сервер разработки, всё должно работать так же, как и раньше.

Использование миксинов

Одним из больших преимуществ использования видов представлений на основе классов является то, что это позволяет нам легко комбинировать многократно используемые фрагменты поведения.

Операции создания/получения/обновления/удаления, которые мы использовали до сих пор, будут довольно похожи для любых представлений API, основанных на модели, которые мы создадим. Эти фрагменты общего поведения реализованы в классах-миксинах REST framework.

Давайте посмотрим, как мы можем комбинировать представления, используя классы-миксины. Вот наш 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)

Мы немного остановимся, чтобы изучить, что происходит здесь. Мы создаём наше представление, используя GenericAPIView, и добавляем ListModelMixin и CreateModelMixin.

Базовый класс предоставляет основную функциональность, а классы-миксины обеспечивают .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() действий.

Использование универсальных видов представлений на основе классов

Используя классы-миксины, мы переписали представления, чтобы использовать немного меньше кода, чем раньше, но мы можем сделать ещё один шаг вперёд. REST framework предоставляет набор уже смешанных универсальных представлений, которые мы можем использовать, чтобы ещё больше сократить наш 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

Вау, это довольно лаконично. Мы получили много чего бесплатно, и наш код выглядит хорошо, чисто и соответствует стилю Django.

Далее мы перейдём к части 4 урока, где рассмотрим, как можно обрабатывать аутентификацию и разрешения для нашего API.

Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/tutorial/3-class-based-views/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API