training-web.ruГлавнаяКатегорииО насКарта сайтаПоискТёмная тема

Категории

Базовый класс Views в django-rest-framework

Создано: 17 июня 2019Автор: Егор Астапов1355 просмотровСложность: легкий

Продолжаю переводить официальное руководство по django-rest-framework. Статья Tutorial 3: Class-based Views или базовый класс Views.

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

Переписываем наш API, используя базовый класс views

Начнем с перезаписи основного представления как представления на основе классов. Все это включает немного рефакторинга views.py.


# view
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.


# view
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 когда мы используем класс на основе представлений.


# 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//', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

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

Используем миксины

Одним из больших преимуществ использования представлений на основе классов является то, что он позволяет нам легко создавать многоразовые куски поведения. Операции create/retrieve/update/delete, которые мы использовали до сих пор, будут очень похожи на любые созданные нами представления API с поддержкой моделей. Эти биты общего поведения реализованы в классах mixin Rest framework. Давайте посмотрим, как мы можем составить представления с помощью классов mixin. Вот наши views.py опять модуль.


# 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.

Базовый класс предоставляет основные функциональные возможности, а классы mixin предоставляют .list() и .create() действия. Затем мы явно привязываем методы get и post к соответствующим действиям. Пока все достаточно просто.


# views.py
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 для предоставления основных функций и добавляем mixins для .retrieve(), .update() и .destroy() действий.

Использование универсального базового класса в представлениях

Using generic class-based views

Использование универсальных представлений на основе классов. Используя классы mixin, мы переписали представления, чтобы использовать немного меньше кода, чем раньше, но мы можем сделать еще один шаг вперед. Rest framework предоставляет набор уже смешанных общих представлений, которые можно использовать для обрезки views.py модуля еще больше.


# 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.

Комментарии

реклама