Представления-классы
Мы также можем написать наши представления API, используя представления-классы, а не представления-функции. Как мы далее убедимся это мощный паттерн, который позволяет многократно использовать общий функционал и соблюдать принцип [DRY (Don't repeat youself)](https://ru.wikipedia.org/wiki/Don't_repeat_yourself).

Применение представлений-классов к нашему API

Прежде всего перепишем наше корневое представление таким образом, чтобы оно использовало классы. Для этого нужно лишь немного изменить содержимое snippets/views.py.
1
from snippets.models import Snippet
2
from snippets.serializers import SnippetSerializer
3
from django.http import Http404
4
from rest_framework.views import APIView
5
from rest_framework.response import Response
6
from rest_framework import status
7
8
9
class SnippetList(APIView):
10
"""
11
Перечисляет все сниппеты или создает новый сниппет.
12
"""
13
def get(self, request, format=None):
14
snippets = Snippet.objects.all()
15
serializer = SnippetSerializer(snippets, many=True)
16
return Response(serializer.data)
17
18
def post(self, request, format=None):
19
serializer = SnippetSerializer(data=request.data)
20
if serializer.is_valid():
21
serializer.save()
22
return Response(serializer.data, status=status.HTTP_201_CREATED)
23
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Copied!
Как видите, это было несложно. Результат не сильно отличается от того, что было раньше, но зато теперь мы добились лучшего разделения между разными HTTP методами. Нам также потребуется внести изменения в экземпляр представления в snippets/views.py.
1
class SnippetDetail(APIView):
2
"""
3
Извлекает, обновляет или удаляет экземпляр сниппета.
4
"""
5
def get_object(self, pk):
6
try:
7
return Snippet.objects.get(pk=pk)
8
except Snippet.DoesNotExist:
9
raise Http404
10
11
def get(self, request, pk, format=None):
12
snippet = self.get_object(pk)
13
serializer = SnippetSerializer(snippet)
14
return Response(serializer.data)
15
16
def put(self, request, pk, format=None):
17
snippet = self.get_object(pk)
18
serializer = SnippetSerializer(snippet, data=request.data)
19
if serializer.is_valid():
20
serializer.save()
21
return Response(serializer.data)
22
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
23
24
def delete(self, request, pk, format=None):
25
snippet = self.get_object(pk)
26
snippet.delete()
27
return Response(status=status.HTTP_204_NO_CONTENT)
Copied!
Выглядит неплохо! Опять же, это очень похоже на представления-функции. Нам потребуется немного изменить наш файл snippets/urls.py, так как теперь мы используем представления на основе классов.
1
from django.conf.urls import url
2
from rest_framework.urlpatterns import format_suffix_patterns
3
from snippets import views
4
5
urlpatterns = [
6
url(r'^snippets/#x27;, views.SnippetList.as_view()),
7
url(r'^snippets/(?P<pk>[0-9]+)/#x27;, views.SnippetDetail.as_view()),
8
]
9
10
urlpatterns = format_suffix_patterns(urlpatterns)
Copied!
Вот и все. Если Вы запустите сервер разработки, то все будет работать точно так же, как и до этого.

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

Одно из главных приемуществ использования представлений-классов заключается в том, что такой подход без труда позволяет нам компоновать повторно используемые элементы логики.
Операции create/retrieve/update/delete, которые мы использовали выше, будут аналогичными для любых представлений на основе API, которые мы создадим. Эти общие элементы встроены в классы примесей (mixin classes) REST framework.
Давайте посмотрим, как можно написать наши представления с помошью классов примесей. Снова откроем модуль snippets/views.py.
1
from snippets.models import Snippet
2
from snippets.serializers import SnippetSerializer
3
from rest_framework import mixins
4
from rest_framework import generics
5
6
class SnippetList(mixins.ListModelMixin,
7
mixins.CreateModelMixin,
8
generics.GenericAPIView):
9
queryset = Snippet.objects.all()
10
serializer_class = SnippetSerializer
11
12
def get(self, request, *args, **kwargs):
13
return self.list(request, *args, **kwargs)
14
15
def post(self, request, *args, **kwargs):
16
return self.create(request, *args, **kwargs)
Copied!
Рассмотрим подробнее, что здесь произошло. Мы строим наше представление с помощью GenericAPIView и добавляем ListModelMixin и CreateModelMixin.
Базовый класс предоставялет основной функционал, в то время как классы примесей дают операции .list() и .create(). После этого мы явно привязываем методы get и post для соответствующих действий. Пока что все довольно просто.
1
class SnippetDetail(mixins.RetrieveModelMixin,
2
mixins.UpdateModelMixin,
3
mixins.DestroyModelMixin,
4
generics.GenericAPIView):
5
queryset = Snippet.objects.all()
6
serializer_class = SnippetSerializer
7
8
def get(self, request, *args, **kwargs):
9
return self.retrieve(request, *args, **kwargs)
10
11
def put(self, request, *args, **kwargs):
12
return self.update(request, *args, **kwargs)
13
14
def delete(self, request, *args, **kwargs):
15
return self.destroy(request, *args, **kwargs)
Copied!
Мы снова используем класс GenericAPIView для основного функционала и добавляем примеси, чтобы получить доступ к операциям .retrieve(), .update() и .destroy().

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

С помощью классов примесей мы переписали наши представления и немного оптимизировали код, но можно пойти еще дальше. REST framework включает набор универсальных представлений, с помощью которых можно еще сильнее сократить наш модуль snippets/views.py.
1
from snippets.models import Snippet
2
from snippets.serializers import SnippetSerializer
3
from rest_framework import generics
4
5
6
class SnippetList(generics.ListCreateAPIView):
7
queryset = Snippet.objects.all()
8
serializer_class = SnippetSerializer
9
10
11
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
12
queryset = Snippet.objects.all()
13
serializer_class = SnippetSerializer
Copied!
Как говорится "Краткость - сестра таланта". Мы без труда сократили наш код, чтобы он выглядел опрятно и читаемо в соответсвии с идеологией Django.
В 4 части руководства мы рассмотрим темы аутентификации и доступа для нашего API.
Last modified 1yr ago