Spec-Zone.ru › Django REST Framework

Урок 5: Связи и гиперссылочные API

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

Создание конечной точки для корня нашего API

Сейчас у нас есть конечные точки для 'фрагментов' и 'пользователей', но у нас нет единой точки входа в наше API. Для создания такой точки мы будем использовать стандартную функцию-представление и декоратор @api_view , который мы ввели ранее. В ваш snippets/views.py добавьте:

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse


@api_view(['GET'])
def api_root(request, format=None):
    return Response({
        'users': reverse('user-list', request=request, format=format),
        'snippets': reverse('snippet-list', request=request, format=format)
    })

Здесь следует обратить внимание на два момента. Во-первых, мы используем функцию reverse REST framework для возвращения полностью квалифицированных URL-адресов; во-вторых, шаблоны URL определяются удобными именами, которые мы объявим позже в нашем snippets/urls.py.

Создание конечной точки для выделенных фрагментов

Другой очевидной частью, которая все еще отсутствует в нашем API pastebin, являются конечные точки для выделения кода.

В отличие от всех остальных конечных точек API, мы не хотим использовать JSON, а вместо этого представим HTML-представление. REST framework предоставляет два стиля рендеринга HTML: один для рендеринга HTML с использованием шаблонов, другой для рендеринга предварительно сгенерированного HTML. Мы хотим использовать второй рендерер для этой конечной точки.

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

Вместо использования конкретного универсального представления мы будем использовать базовый класс для представления экземпляров и создадим свой собственный метод .get(). В ваш snippets/views.py добавьте:

from rest_framework import renderers

class SnippetHighlight(generics.GenericAPIView):
    queryset = Snippet.objects.all()
    renderer_classes = [renderers.StaticHTMLRenderer]

    def get(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

Как обычно, нам нужно добавить новые представления, которые мы создали, в наш URLconf. Мы добавим шаблон URL для нашего нового корня API в snippets/urls.py:

path('', views.api_root),

Затем добавим шаблон URL для выделения фрагментов кода:

path('snippets/<int:pk>/highlight/', views.SnippetHighlight.as_view()),

Гиперссылочные API

Работа с отношениями между сущностями — один из наиболее сложных аспектов проектирования веб-API. Существует ряд различных способов представления отношений:

  • Использование первичных ключей.
  • Использование гиперссылок между сущностями.
  • Использование уникального идентификатора slug у связанной сущности.
  • Использование стандартного строкового представления связанной сущности.
  • Вложение связанной сущности в родительское представление.
  • Другое пользовательское представление.

REST framework поддерживает все эти стили и может применять их к прямым или обратным отношениям, или применять их к пользовательским менеджерам, таким как универсальные внешние ключи.

В данном случае мы хотим использовать гиперссылочный стиль между сущностями. Для этого мы изменим наши сериализаторы, расширив HyperlinkedModelSerializer вместо существующего ModelSerializer.

В HyperlinkedModelSerializer есть следующие отличия от ModelSerializer:

  • По умолчанию он не включает поле id.
  • Он включает поле url , используя HyperlinkedIdentityField.
  • Связи используют HyperlinkedRelatedField, а не PrimaryKeyRelatedField.

Мы можем легко переписать наши существующие сериализаторы, чтобы использовать гиперссылки. В ваш snippets/serializers.py добавьте:

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')

    class Meta:
        model = Snippet
        fields = ['url', 'id', 'highlight', 'owner',
                  'title', 'code', 'linenos', 'language', 'style']


class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)

    class Meta:
        model = User
        fields = ['url', 'id', 'username', 'snippets']

Обратите внимание, что мы также добавили новое поле 'highlight'. Это поле имеет тот же тип, что и поле url , за исключением того, что оно указывает на шаблон URL 'snippet-highlight' вместо шаблона URL 'snippet-detail'.

Поскольку мы включили URL-адреса с суффиксом формата, например, '.json', нам также нужно указать в поле highlight , что любые гиперссылки с суффиксом формата, которые оно возвращает, должны использовать суффикс '.html'.

Обеспечение именования шаблонов URL

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

  • Корень нашего API относится к 'user-list' и 'snippet-list'.
  • Наш сериализатор фрагментов включает поле, которое относится к 'snippet-highlight'.
  • Наш сериализатор пользователей включает поле, которое относится к 'snippet-detail'.
  • Наши сериализаторы фрагментов и пользователей включают поля 'url' , которые по умолчанию будут ссылаться на '{model_name}-detail', что в данном случае будет 'snippet-detail' и 'user-detail'.

После добавления всех этих имен в наш URLconf, наш окончательный файл snippets/urls.py должен выглядеть так:

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

# API endpoints
urlpatterns = format_suffix_patterns([
    path('', views.api_root),
    path('snippets/',
        views.SnippetList.as_view(),
        name='snippet-list'),
    path('snippets/<int:pk>/',
        views.SnippetDetail.as_view(),
        name='snippet-detail'),
    path('snippets/<int:pk>/highlight/',
        views.SnippetHighlight.as_view(),
        name='snippet-highlight'),
    path('users/',
        views.UserList.as_view(),
        name='user-list'),
    path('users/<int:pk>/',
        views.UserDetail.as_view(),
        name='user-detail')
])

Добавление пагинации

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

Мы можем изменить стандартный стиль списка на пагинацию, немного изменив файл tutorial/settings.py. Добавьте следующие настройки:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

Обратите внимание, что все настройки в REST framework сгруппированы в одном словаре настроек с именем REST_FRAMEWORK, что помогает изолировать их от других настроек вашего проекта.

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

Просмотр API

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

Вы также сможете увидеть ссылки 'выделить' для экземпляров фрагментов, которые приведут вас к HTML-представлениям выделенного кода.

В части 6 урока мы рассмотрим, как использовать ViewSets и маршрутизаторы для сокращения кода, необходимого для создания нашего API.

Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/

Spec-Zone.ru

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