Spec-Zone.ru › Django REST Framework

Урок 6: ViewSets и маршрутизаторы

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

ViewSet классы почти идентичны View классам, за исключением того, что они предоставляют операции, такие как retrieve, или update, а не обработчики методов, такие как get или put.

Класс ViewSet связывается с набором обработчиков методов только в последний момент, когда он преобразуется в набор представлений, обычно с помощью класса Router , который обрабатывает сложность определения URL-конфигурации за вас.

Рефакторинг для использования ViewSets

Давайте возьмём наш текущий набор представлений и перепишем их в виде наборов представлений.

Прежде всего, давайте перепишем наши UserList и UserDetail классы в один класс UserViewSet. В файле snippets/views.py мы можем удалить два класса представления и заменить их одним классом ViewSet:

from rest_framework import viewsets


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `retrieve` actions.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

Здесь мы использовали класс ReadOnlyModelViewSet для автоматического предоставления стандартных операций «только для чтения». Мы всё ещё устанавливаем атрибуты queryset и serializer_class так же, как и при использовании обычных представлений, но больше не нужно предоставлять ту же информацию двум отдельным классам.

Далее мы собираемся заменить классы представлений SnippetList, SnippetDetail и SnippetHighlight. Мы можем удалить три представления и снова заменить их одним классом.

from rest_framework import permissions
from rest_framework import renderers
from rest_framework.decorators import action
from rest_framework.response import Response


class SnippetViewSet(viewsets.ModelViewSet):
    """
    This ViewSet automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.

    Additionally we also provide an extra `highlight` action.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

На этот раз мы использовали класс ModelViewSet для получения полного набора стандартных операций чтения и записи.

Обратите внимание, что мы также использовали декоратор @action для создания пользовательского действия, названного highlight. Этот декоратор можно использовать для добавления любых пользовательских конечных точек, которые не подходят под стандартный стиль create/update/delete.

Пользовательские действия, использующие декоратор @action, по умолчанию будут отвечать на запросы GET. Мы можем использовать аргумент methods, если нам нужно действие, которое отвечает на запросы POST.

URL-адреса для пользовательских действий по умолчанию зависят от имени самого метода. Если вы хотите изменить способ построения URL-адресов, вы можете включить url_path в качестве аргумента декоратора.

Явное привязывание ViewSets к URL-адресам

Методы-обработчики связываются с действиями только при определении URLConf. Чтобы увидеть, что происходит за кулисами, давайте сначала явным образом создадим набор представлений из наших ViewSets.

В файле snippets/urls.py мы связываем наши классы ViewSet с набором конкретных представлений.

from rest_framework import renderers

from snippets.views import api_root, SnippetViewSet, UserViewSet

snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})

Обратите внимание, как мы создаём несколько представлений из каждого класса ViewSet, привязывая HTTP-методы к необходимому действию для каждого представления.

Теперь, когда мы связали наши ресурсы с конкретными представлениями, мы можем зарегистрировать представления в URL-конфигурации как обычно.

urlpatterns = format_suffix_patterns([
    path('', api_root),
    path('snippets/', snippet_list, name='snippet-list'),
    path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
    path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
    path('users/', user_list, name='user-list'),
    path('users/<int:pk>/', user_detail, name='user-detail')
])

Использование маршрутизаторов

Поскольку мы используем классы ViewSet вместо классов View, нам на самом деле не нужно самостоятельно проектировать URL-конфигурацию. Соглашения по подключению ресурсов к представлениям и URL-адресам можно обрабатывать автоматически с помощью класса Router . Всё, что нам нужно сделать, это зарегистрировать соответствующие наборы представлений с маршрутизатором и позволить ему сделать остальное.

Вот наш переработанный файл snippets/urls.py.

from django.urls import path, include
from rest_framework.routers import DefaultRouter

from snippets import views

# Create a router and register our ViewSets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet, basename='snippet')
router.register(r'users', views.UserViewSet, basename='user')

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

Регистрация ViewSets с маршрутизатором аналогична предоставлению urlpattern. Мы включаем два аргумента — префикс URL-адреса для представлений и сам набор представлений.

Класс DefaultRouter , который мы используем, также автоматически создаёт для нас корневое представление API, поэтому мы можем удалить функцию api_root из нашего модуля views.

Сравнительный анализ использования представлений и ViewSets

Использование ViewSets может быть очень полезной абстракцией. Оно помогает обеспечить согласованность URL-конвенций в вашем API, минимизирует количество необходимого кода и позволяет сосредоточиться на взаимодействиях и представлениях вашего API, а не на деталях URL-конфигурации.

Это не означает, что это всегда правильный подход. Существует аналогичный набор компромиссов, которые следует учитывать, как и при использовании представлений на основе классов вместо представлений на основе функций. Использование ViewSets менее явное, чем создание представлений API по отдельности.

Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/

Spec-Zone.ru

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