Маршрутизаторы¶
Маршрутизация ресурсов позволяет быстро объявить все общие маршруты для данного ресурсного контроллера. Вместо того чтобы объявлять отдельные маршруты для вашего индекса… ресурсный маршрут объявляет их в одной строке кода.
‒ Ruby on Rails Documentation
Некоторые веб-фреймворки, такие как Rails, предоставляют функциональность для автоматического определения того, как URL-адреса приложения должны быть сопоставлены с логикой, которая занимается обработкой входящих запросов.
Фреймворк REST добавляет в Django поддержку автоматической маршрутизации URL и предоставляет вам простой, быстрый и последовательный способ подключения логики представления к набору URL.
Использование¶
Вот пример простого URL conf, в котором используется 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 namespaces docs и ** ``include:doc:` API reference <https://docs.djangoproject.com/en/2.0/ref/urls/#include>` в Django.
Примечание: При использовании пространства имен с гиперссылками в сериализаторах вам также необходимо убедиться, что все параметры view_name
в сериализаторах правильно отражают пространство имен. В приведенных выше примерах вам нужно включить такой параметр, как view_name='app_name:user-detail'
для полей сериализатора, гиперссылка на которые ведет к детальному представлению пользователя.
Автоматическая генерация view_name
использует шаблон типа %(model_name)-detail
. Если только имена ваших моделей не противоречат друг другу, вам лучше ***не **расставлять имена в представлениях Django REST Framework при использовании сериализаторов с гиперссылками.
Маршрутизация для дополнительных действий¶
Набор представлений может mark extra actions for routing, украсив метод декоратором @action
. Эти дополнительные действия будут включены в сгенерированные маршруты. Например, дан метод set_password
на классе UserViewSet
:
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 Style | HTTP Method | Action | URL Name |
---|---|---|---|
{prefix}/ | GET | list | {basename}-list |
POST | create | ||
{prefix}/{url_path}/ | GET, or as specified by `methods` argument | `@action(detail=False)` decorated method | {basename}-{url_name} |
{prefix}/{lookup}/ | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{url_path}/ | GET, or as specified by `methods` argument | `@action(detail=True)` decorated method | {basename}-{url_name} |
По умолчанию URL, созданные с помощью SimpleRouter
, дополняются косой чертой. Это поведение можно изменить, установив аргумент trailing_slash
в False
при инстанцировании маршрутизатора. Например:
router = SimpleRouter(trailing_slash=False)
В Django косые черты являются традиционными, но не используются по умолчанию в некоторых других фреймворках, таких как Rails. Какой стиль использовать - это в основном вопрос предпочтений, хотя некоторые javascript-фреймворки могут ожидать определенного стиля маршрутизации.
Маршрутизатор будет соответствовать значениям поиска, содержащим любые символы, кроме косой черты и точки. Для более строгого (или мягкого) шаблона поиска установите атрибут lookup_value_regex
в наборе представлений. Например, можно ограничить поиск действительными UUID:
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'
DefaultRouter¶
Этот маршрутизатор похож на SimpleRouter
, как описано выше, но дополнительно включает корневое представление API по умолчанию, которое возвращает ответ, содержащий гиперссылки на все представления списка. Он также генерирует маршруты для необязательных суффиксов формата стиля .json
.
URL Style | HTTP Method | Action | URL Name |
---|---|---|---|
[.format] | GET | automatically generated root view | api-root |
{prefix}/[.format] | GET | list | {basename}-list |
POST | create | ||
{prefix}/{url_path}/[.format] | GET, or as specified by `methods` argument | `@action(detail=False)` decorated method | {basename}-{url_name} |
{prefix}/{lookup}/[.format] | GET | retrieve | {basename}-detail |
PUT | update | ||
PATCH | partial_update | ||
DELETE | destroy | ||
{prefix}/{lookup}/{url_path}/[.format] | GET, or as specified by `methods` argument | `@action(detail=True)` decorated method | {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}
- Поле поиска, используемое для сопоставления с одним экземпляром.{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 Method | Action | URL Name |
---|---|---|---|
/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. Зарегистрированные кортежи prefix, viewset и basename могут быть проверены путем обращения к атрибуту self.registry
.
Вы также можете переопределить метод get_default_basename(self, viewset)
, или всегда явно задавать аргумент basename
при регистрации ваших наборов представлений в маршрутизаторе.
Сторонние пакеты¶
Также доступны следующие пакеты сторонних производителей.
Вложенные маршрутизаторы DRF¶
drf-nested-routers package предоставляет маршрутизаторы и поля отношений для работы с вложенными ресурсами.
ModelRouter (wq.db.rest)¶
wq.db package предоставляет расширенный ModelRouter класс (и экземпляр синглтона), который расширяет DefaultRouter
с register_model()
API. Как и в admin.site.register
в Django, единственным необходимым аргументом для rest.router.register_model
является класс модели. Разумные значения по умолчанию для префикса url, сериализатора и набора представлений будут выведены из модели и глобальной конфигурации.
from wq.db import rest
from myapp.models import MyModel
rest.router.register_model(MyModel)
DRF-расширения¶
** ``DRF-extensions:doc:` package <https://chibisov.github.io/drf-extensions/docs/>` обеспечивает routers для создания nested viewsets с customizable endpoint names.