Spec-Zone.ru › Django REST Framework

Маршрутизаторы

Маршрутизация ресурсов позволяет быстро объявлять все общие маршруты для заданного контроллера ресурсов. Вместо объявления отдельных маршрутов для индекса... маршрут ресурсов объявляет их в одной строке кода.

— Документация Ruby on Rails

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

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

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

Вот пример простого файла конфигурации URL, который использует SimpleRouter.

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls

В метод register() необходимо передать два обязательных аргумента:

  • prefix - Префикс URL-адреса, который следует использовать для этого набора маршрутов.
  • viewset - Класс представления.

Необязательно, вы также можете указать дополнительный аргумент:

  • basename - Базовый элемент для имен URL-адресов, которые создаются. Если не задан, имя базового элемента будет автоматически сгенерировано на основе атрибута queryset представления, если он есть. Обратите внимание, что если представление не включает атрибут queryset, вам необходимо установить basename при регистрации представления.

Приведенный выше пример сгенерирует следующие шаблоны URL-адресов:

  • Шаблон URL-адреса: ^users/$ Имя: 'user-list'
  • Шаблон URL-адреса: ^users/{pk}/$ Имя: 'user-detail'
  • Шаблон URL-адреса: ^accounts/$ Имя: 'account-list'
  • Шаблон URL-адреса: ^accounts/{pk}/$ Имя: 'account-detail'

Примечание: Аргумент basename используется для указания начальной части шаблона имени представления. В приведенном выше примере это часть user или account.

Обычно вам не нужно указывать аргумент basename, но если у вас есть представление, в котором вы определили пользовательский метод get_queryset, то у представления может отсутствовать атрибут .queryset. Если вы попытаетесь зарегистрировать это представление, вы увидите ошибку такого типа:

'basename' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.

Это означает, что вам необходимо явно задать аргумент basename при регистрации представления, поскольку он не может быть автоматически определен по имени модели.

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

Атрибут .urls экземпляра маршрутизатора — это просто стандартный список шаблонов URL-адресов. Существует несколько различных стилей, как можно включить эти URL-адреса.

Например, вы можете добавить router.urls к списку существующих представлений...

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
]

urlpatterns += router.urls

В качестве альтернативы можно использовать функцию Django include, как показано ниже...

urlpatterns = [
    path('forgot-password', ForgotPasswordFormView.as_view()),
    path('', include(router.urls)),
]

Вы можете использовать include с пространством имен приложения:

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'app_name'))),
]

Или и с пространством имен приложения, и экземпляра:

urlpatterns = [
    path('forgot-password/', ForgotPasswordFormView.as_view()),
    path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
]

См. документацию по пространствам имен URL-адресов Django здесь и ссылку на API include здесь для получения дополнительной информации.

Примечание: При использовании именования с гиперссылочными сериализаторами также необходимо убедиться, что все параметры view_name в сериализаторах правильно отражают пространство имен. В приведенных выше примерах вам потребуется включить параметр, такой как view_name='app_name:user-detail' для полей сериализатора, гиперссылками на представление деталей пользователя.

Автоматическое создание view_name использует шаблон, подобный %(model_name)-detail. Если имена моделей не конфликтуют, лучше не добавлять пространств имен для представлений Django REST Framework при использовании гиперссылочных сериализаторов.

Маршрутизация для дополнительных действий

Представление может пометить дополнительные действия для маршрутизации, используя декоратор @action. Эти дополнительные действия будут включены в сгенерированные маршруты. Например, если у класса UserViewSet есть метод set_password,

from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action

class UserViewSet(ModelViewSet):
    ...

    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf])
    def set_password(self, request, pk=None):
        ...

будет сгенерирован следующий маршрут:

  • Шаблон URL-адреса: ^users/{pk}/set_password/$
  • Имя URL-адреса: 'user-set-password'

По умолчанию шаблон URL-адреса основан на имени метода, а имя URL-адреса — это комбинация ViewSet.basename и имени метода с дефисом. Если вы не хотите использовать значения по умолчанию для одного из этих параметров, вместо этого можно указать аргументы url_path и url_name в декоратор @action.

Например, если вы хотите изменить URL-адрес для нашего пользовательского действия на ^users/{pk}/change-password/$, вы можете написать:

from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action

class UserViewSet(ModelViewSet):
    ...

    @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
            url_path='change-password', url_name='change_password')
    def set_password(self, request, pk=None):
        ...

В этом случае будет сгенерирован следующий шаблон URL-адреса:

  • Путь URL-адреса: ^users/{pk}/change-password/$
  • Имя URL-адреса: 'user-change_password'

Руководство по API

SimpleRouter

Этот маршрутизатор включает маршруты для стандартного набора list, create, retrieve, update, partial_update и destroy действий. Представление также может отмечать дополнительные методы для маршрутизации, используя декоратор @action.

Стиль URL HTTP-метод Действие Имя URL
{prefix}/ GET list {basename}-list
POST create
{prefix}/{url_path}/ GET или как указано в аргументе `methods` Метод, отмеченный декоратором `@action(detail=False)` {basename}-{url_name}
{prefix}/{lookup}/ GET retrieve {basename}-detail
PUT update
PATCH partial_update
DELETE destroy
{prefix}/{lookup}/{url_path}/ GET или как указано в аргументе `methods` Метод, отмеченный декоратором `@action(detail=True)` {basename}-{url_name}

По умолчанию URL-адреса, созданные с помощью SimpleRouter, дополняются слешем. Это поведение можно изменить, установив аргумент trailing_slash в значение False при создании маршрутизатора. Например:

router = SimpleRouter(trailing_slash=False)

Слеши являются стандартными в Django, но не используются по умолчанию в некоторых других фреймворках, таких как Rails. Выбор стиля в основном зависит от предпочтений, хотя некоторые фреймворки JavaScript могут ожидать определённого стиля маршрутизации.

По умолчанию URL-адреса, созданные с помощью SimpleRouter, используют регулярные выражения. Это поведение можно изменить, установив аргумент use_regex_path в значение False при создании маршрутизатора, в этом случае используются конвертеры путей. Например:

router = SimpleRouter(use_regex_path=False)

Примечание: use_regex_path=False работает только с Django 2.x и выше, так как эта функция была введена в 2.0.0. См. примечание к выпуску.

Маршрутизатор будет сопоставлять значения lookup, содержащие любые символы, кроме слешей и точек. Для более ограниченного (или более свободного) шаблона lookup установите атрибут lookup_value_regex в представлении или lookup_value_converter при использовании конвертеров путей. Например, можно ограничить lookup допустимыми UUID:

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'my_model_id'
    lookup_value_regex = '[0-9a-f]{32}'

class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    lookup_field = 'my_model_uuid'
    lookup_value_converter = 'uuid'

DefaultRouter

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

Стиль URL HTTP-метод Действие Имя URL
[.format] GET автоматически сгенерированное корневое представление api-root
{prefix}/[.format] GET list {basename}-list
POST create
{prefix}/{url_path}/[.format] GET или как указано в аргументе `methods` Метод, отмеченный декоратором `@action(detail=False)` {basename}-{url_name}
{prefix}/{lookup}/[.format] GET retrieve {basename}-detail
PUT update
PATCH partial_update
DELETE destroy
{prefix}/{lookup}/{url_path}/[.format] GET или как указано в аргументе `methods` Метод, отмеченный декоратором `@action(detail=True)` {basename}-{url_name}

Как и в случае с SimpleRouter, слеши в маршрутах URL-адресов можно удалить, установив аргумент trailing_slash в значение False при создании маршрутизатора.

router = DefaultRouter(trailing_slash=False)

Настраиваемые маршрутизаторы

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

Простейший способ реализации пользовательского маршрутизатора — это наследование от одного из существующих классов маршрутизаторов. Атрибут .routes используется для шаблонизации URL-шаблонов, которые будут сопоставлены с каждым представлением. Атрибут .routes — это список кортежей Route с именами.

Аргументы кортежа Route:

url: Строка, представляющая маршрутируемый URL-адрес. Может включать следующие форматы строк:

  • {prefix} - Префикс URL-адреса, который следует использовать для этого набора маршрутов.
  • {lookup} - Поле lookup, используемое для сопоставления с одним экземпляром.
  • {trailing_slash} - Либо '/', либо пустая строка, в зависимости от аргумента trailing_slash.

mapping: Сопоставление имен HTTP-методов с методами представления.

name: Имя URL-адреса, используемое в вызовах reverse. Может включать следующую строку формата:

  • {basename} - Базовый элемент для имен созданных URL-адресов.

initkwargs: Словарь дополнительных аргументов, которые следует передать при создании представления. Обратите внимание, что аргументы detail, basename, и suffix зарезервированы для интроспекции представления и также используются API для просмотра для генерации имени представления и ссылок хлебных крошек.

Настройка динамических маршрутов

Также можно настроить маршрутизацию декоратора @action. Включите именованную кортеж DynamicRoute в список .routes, задав аргумент detail соответствующим образом для маршрутов на основе списка и маршрутов на основе подробностей. В дополнение к detail, аргументы для DynamicRoute следующие:

url: Строка, представляющая URL, который нужно маршрутизировать. Может содержать те же форматы строк, что и Route, а также принимает форматную строку {url_path}.

name: Имя URL, используемое в вызовах reverse. Может содержать следующие форматы строк:

  • {basename} - База для имен URL, которые создаются.
  • {url_name} - Предоставленный url_name для @action.

initkwargs: Словарь дополнительных аргументов, которые необходимо передать при создании представления.

Пример

Следующий пример будет маршрутизировать только к действиям list и retrieve, и не использует соглашение с косой чертой в конце.

from rest_framework.routers import Route, DynamicRoute, SimpleRouter

class CustomReadOnlyRouter(SimpleRouter):
    """
    A router for read-only APIs, which doesn't use trailing slashes.
    """
    routes = [
        Route(
            url=r'^{prefix}$',
            mapping={'get': 'list'},
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        Route(
            url=r'^{prefix}/{lookup}$',
            mapping={'get': 'retrieve'},
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Detail'}
        ),
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        )
    ]

Давайте посмотрим на маршруты, которые сгенерирует наш CustomReadOnlyRouter для простого набора представлений.

views.py:

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    A viewset that provides the standard actions
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_field = 'username'

    @action(detail=True)
    def group_names(self, request, pk=None):
        """
        Returns a list of all the group names that the given
        user belongs to.
        """
        user = self.get_object()
        groups = user.groups.all()
        return Response([group.name for group in groups])

urls.py:

router = CustomReadOnlyRouter()
router.register('users', UserViewSet)
urlpatterns = router.urls

Будут сгенерированы следующие сопоставления...

URL HTTP Метод Действие Имя URL
/users GET list user-list
/users/{username} GET retrieve user-detail
/users/{username}/group_names GET group_names user-group-names

Для другого примера установки атрибута .routes см. исходный код класса SimpleRouter.

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

Если вы хотите предоставить полностью настраиваемое поведение, вы можете переопределить BaseRouter и переопределить метод get_urls(self). Метод должен проанализировать зарегистрированные наборы представлений и вернуть список шаблонов URL. Зарегистрированный префикс, набор представлений и кортежи с базовым именем можно просмотреть, обратившись к атрибуту self.registry.

Вы также можете переопределить метод get_default_basename(self, viewset), или же всегда явно установить аргумент basename при регистрации наборов представлений с маршрутизатором.

Пакеты сторонних разработчиков

Также доступны следующие пакеты сторонних разработчиков.

Вложенные маршрутизаторы DRF

Пакет drf-nested-routers предоставляет маршрутизаторы и поля отношений для работы со вложенными ресурсами.

ModelRouter (wq.db.rest)

Пакет wq.db предоставляет расширенный класс ModelRouter (и экземпляр-синглтон), который расширяет DefaultRouter с API register_model(). Подобно Django's admin.site.register, единственным необходимым аргументом для rest.router.register_model является класс модели. Приемлемые значения по умолчанию для префикса URL, сериализатора и набора представлений будут выведены из модели и глобальной конфигурации.

from wq.db import rest
from myapp.models import MyModel

rest.router.register_model(MyModel)

DRF-extensions

Пакет DRF-extensions предоставляет маршрутизаторы для создания вложенных наборов представлений, контроллеров уровня коллекции с настраиваемыми именами точек входа.

routers.py

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

Spec-Zone.ru

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