Рендереры

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

Django documentation

REST framework включает в себя несколько встроенных классов Renderer, которые позволяют возвращать ответы с различными типами медиа. Также имеется поддержка определения собственных пользовательских рендереров, что дает вам гибкость в разработке собственных типов медиа.

Как определяется рендерер

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

Основной процесс согласования содержимого включает изучение заголовка Accept запроса, чтобы определить, какие типы медиа ожидаются в ответе. По желанию, суффиксы формата в URL могут быть использованы для явного запроса определенного представления. Например, URL http://example.com/api/users_count.json может быть конечной точкой, которая всегда возвращает данные в формате JSON.

Для получения дополнительной информации см. документацию по content negotiation.

Настройка рендеринга

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

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

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

from django.contrib.auth.models import User
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView

class UserCountView(APIView):
    """
    A view that returns the count of active users in JSON.
    """
    renderer_classes = [JSONRenderer]

    def get(self, request, format=None):
        user_count = User.objects.filter(active=True).count()
        content = {'user_count': user_count}
        return Response(content)

Или, если вы используете декоратор @api_view с представлениями, основанными на функциях.

@api_view(['GET'])
@renderer_classes([JSONRenderer])
def user_count_view(request, format=None):
    """
    A view that returns the count of active users in JSON.
    """
    user_count = User.objects.filter(active=True).count()
    content = {'user_count': user_count}
    return Response(content)

Упорядочивание классов рендеринга

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

Например, если ваш API обслуживает JSON-ответы и HTML-просмотр, вы можете захотеть сделать JSONRenderer вашим рендерером по умолчанию, чтобы отправлять JSON ответы клиентам, которые не указывают заголовок Accept.

Если ваш API включает представления, которые могут обслуживать как обычные веб-страницы, так и ответы API в зависимости от запроса, то вы можете сделать TemplateHTMLRenderer рендерером по умолчанию, чтобы хорошо играть со старыми браузерами, которые посылают broken accept headers.


Справочник по API

JSONRenderer

Переводит данные запроса в JSON , используя кодировку utf-8.

Обратите внимание, что стиль по умолчанию включает символы юникода и отображает ответ, используя компактный стиль без лишних пробелов:

{"unicode black star":"★","value":999}

Клиент может дополнительно включить параметр типа медиа 'indent', в этом случае возвращаемое JSON будет с отступом. Например, Accept: application/json; indent=4.

{
    "unicode black star": "★",
    "value": 999
}

Стиль кодировки JSON по умолчанию может быть изменен с помощью клавиш настройки UNICODE_JSON и COMPACT_JSON.

.media_type : application/json

.format : 'json'

.charset : None

TemplateHTMLRenderer

Рендерит данные в HTML, используя стандартный шаблонный рендеринг Django. В отличие от других рендереров, данные, передаваемые в Response, не нужно сериализовать. Также, в отличие от других рендереров, вы можете захотеть включить аргумент template_name при создании Response.

TemplateHTMLRenderer создаст RequestContext , используя response.data в качестве диктанта контекста, и определит имя шаблона, который будет использоваться для рендеринга контекста.


Примечание: При использовании с представлением, которое использует сериализатор, Response, отправленный для рендеринга, может не быть словарем и должен быть обернут в dict перед возвратом, чтобы TemplateHTMLRenderer смог его отрендерить. Например:

response.data = {'results': response.data}

Имя шаблона определяется (в порядке предпочтения):

  1. Явный аргумент template_name, передаваемый в ответ.

  2. Явный набор атрибутов .template_name для этого класса.

  3. Возвращаемый результат вызова view.get_template_names().

Пример представления, которое использует TemplateHTMLRenderer :

class UserDetail(generics.RetrieveAPIView):
    """
    A view that returns a templated HTML representation of a given user.
    """
    queryset = User.objects.all()
    renderer_classes = [TemplateHTMLRenderer]

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return Response({'user': self.object}, template_name='user_detail.html')

Вы можете использовать TemplateHTMLRenderer либо для возврата обычных HTML-страниц с помощью фреймворка REST, либо для возврата HTML- и API-ответов с одной конечной точки.

Если вы создаете сайты, использующие TemplateHTMLRenderer наряду с другими классами рендеринга, вам следует рассмотреть возможность включения TemplateHTMLRenderer в качестве первого класса в списке renderer_classes, чтобы он был приоритетным даже для браузеров, посылающих плохо сформированные заголовки ACCEPT:.

Дополнительные примеры использования ** *HTML & Forms* Topic Page см. в TemplateHTMLRenderer.

.media_type : text/html

.format : 'html'

.charset : utf-8

См. также: StaticHTMLRenderer

StaticHTMLRenderer

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

Пример представления, которое использует StaticHTMLRenderer :

@api_view(['GET'])
@renderer_classes([StaticHTMLRenderer])
def simple_html_view(request):
    data = '<html><body><h1>Hello, world</h1></body></html>'
    return Response(data)

Вы можете использовать StaticHTMLRenderer либо для возврата обычных HTML-страниц с помощью фреймворка REST, либо для возврата HTML- и API-ответов с одной конечной точки.

.media_type : text/html

.format : 'html'

.charset : utf-8

См. также: TemplateHTMLRenderer

BrowsableAPIRenderer

Рендерит данные в HTML для Browsable API:

The BrowsableAPIRenderer

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

.media_type : text/html

.format : 'api'

.charset : utf-8

.template : 'rest_framework/api.html'

Настройка BrowsableAPIRenderer

По умолчанию содержимое ответа будет отрисовываться рендерером с наивысшим приоритетом, кроме BrowsableAPIRenderer. Если вам нужно настроить это поведение, например, использовать HTML в качестве формата возврата по умолчанию, но использовать JSON в просматриваемом API, вы можете сделать это, переопределив метод get_default_renderer(). Например:

class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
    def get_default_renderer(self, view):
        return JSONRenderer()

AdminRenderer

Рендерит данные в HTML для отображения в стиле администратора:

The AdminRender view

Этот рендерер подходит для веб-интерфейсов в стиле CRUD, которые также должны представлять удобный интерфейс для управления данными.

Обратите внимание, что представления, которые имеют вложенные или списковые сериализаторы для ввода, не будут хорошо работать с AdminRenderer , так как HTML формы не могут правильно их поддерживать.

Примечание : AdminRenderer может включать ссылки на детальные страницы только тогда, когда в данных присутствует правильно настроенный атрибут URL_FIELD_NAME (** url по умолчанию). Для HyperlinkedModelSerializer так и будет, но для ModelSerializer или простых Serializer классов вам нужно будет убедиться, что поле включено явно. Например, здесь мы используем метод models get_absolute_url:

class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)

    class Meta:
        model = Account

.media_type : text/html

.format : 'admin'

.charset : utf-8

.template : 'rest_framework/admin.html'

HTMLFormRenderer

Рендерит данные, возвращаемые сериализатором, в HTML-форму. Вывод этого рендерера не включает заключающие теги <form>, скрытый CSRF-вход или какие-либо кнопки отправки.

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

{% load rest_framework %}

<form action="/submit-report/" method="post">
    {% csrf_token %}
    {% render_form serializer %}
    <input type="submit" value="Save" />
</form>

Для получения дополнительной информации см. документацию HTML & Forms.

.media_type : text/html

.format : 'form'

.charset : utf-8

.template : 'rest_framework/horizontal/form.html'

MultiPartRenderer

Этот рендерер используется для рендеринга данных многочастной формы HTML. Он не подходит в качестве рендеринга ответов , а используется для создания тестовых запросов, используя test client and test request factory фреймворка REST.

.media_type : multipart/form-data; boundary=BoUnDaRyStRiNg

.format : 'multipart'

.charset : utf-8


Пользовательские рендереры

Для реализации пользовательского рендерера необходимо переопределить BaseRenderer , установить свойства .media_type и .format и реализовать метод .render(self, data, media_type=None, renderer_context=None).

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

Аргументы, передаваемые методу .render(), следующие:

Данные запроса, заданные инстанцией Response().

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

В зависимости от заголовка Accept: клиента, он может быть более конкретным, чем атрибут media_type рендерера, и может включать параметры медиатипа. Например, "application/json; nested=true".

Необязательно. Если предоставляется, то это словарь контекстной информации, предоставляемой представлением.

По умолчанию сюда входят следующие ключи: view , request , response , args , kwargs.

Пример

Ниже приведен пример рендеринга обычного текста, который вернет ответ с параметром data в качестве содержимого ответа.

from django.utils.encoding import smart_text
from rest_framework import renderers


class PlainTextRenderer(renderers.BaseRenderer):
    media_type = 'text/plain'
    format = 'txt'

    def render(self, data, media_type=None, renderer_context=None):
        return smart_text(data, encoding=self.charset)

Настройка набора символов

По умолчанию предполагается, что классы рендереров используют кодировку UTF-8. Чтобы использовать другую кодировку, установите атрибут charset на рендерере.

class PlainTextRenderer(renderers.BaseRenderer):
    media_type = 'text/plain'
    format = 'txt'
    charset = 'iso-8859-1'

    def render(self, data, media_type=None, renderer_context=None):
        return data.encode(self.charset)

Обратите внимание, что если класс renderer возвращает строку unicode, то содержимое ответа будет преобразовано в байтстринг классом Response, с атрибутом charset, установленным на renderer, используемом для определения кодировки.

Если рендерер возвращает байтстринг, представляющий необработанное двоичное содержимое, следует установить значение charset None , что обеспечит отсутствие в заголовке ответа Content-Type значения charset.

В некоторых случаях вы также можете установить атрибут render_style на 'binary'. Это также гарантирует, что просматриваемый API не будет пытаться отобразить двоичное содержимое в виде строки.

class JPEGRenderer(renderers.BaseRenderer):
    media_type = 'image/jpeg'
    format = 'jpg'
    charset = None
    render_style = 'binary'

    def render(self, data, media_type=None, renderer_context=None):
        return data

Расширенное использование рендеринга

Вы можете делать довольно гибкие вещи, используя рендереры фреймворка REST. Некоторые примеры…

  • Предоставление плоских или вложенных представлений из одной и той же конечной точки, в зависимости от запрашиваемого типа носителя.

  • Предоставление как обычных веб-страниц HTML, так и ответов API на основе JSON с одних и тех же конечных точек.

  • Укажите несколько типов представления HTML для использования клиентами API.

  • Недоопределение медиатипа рендерера, например, использование media_type = 'image/*' , и использование заголовка Accept для изменения кодировки ответа.

Различное поведение в зависимости от типа СМИ

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

Например:

@api_view(['GET'])
@renderer_classes([TemplateHTMLRenderer, JSONRenderer])
def list_users(request):
    """
    A view that can return JSON or HTML representations
    of the users in the system.
    """
    queryset = Users.objects.filter(active=True)

    if request.accepted_renderer.format == 'html':
        # TemplateHTMLRenderer takes a context dict,
        # and additionally requires a 'template_name'.
        # It does not require serialization.
        data = {'users': queryset}
        return Response(data, template_name='list_users.html')

    # JSONRenderer requires serialized data as normal.
    serializer = UserSerializer(instance=queryset)
    data = serializer.data
    return Response(data)

Недоопределение типа носителя

В некоторых случаях вы можете захотеть, чтобы рендерер обслуживал ряд типов медиа. В этом случае вы можете не указывать типы медиа, на которые он должен реагировать, используя значение media_type, например image/* , или */*.

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

return Response(data, content_type='image/png')

Проектирование типов носителей информации

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

В :doc:`the words of Roy Fielding <https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven>`** , «REST API должен потратить почти все свои описательные усилия на определение типа(ов) медиа, используемых для представления ресурсов и управления состоянием приложения, или на определение расширенных имен отношений и/или гипертекстовой разметки для существующих стандартных типов медиа».

Хорошими примерами пользовательских типов медиа являются использование GitHub пользовательского типа медиа application/vnd.github+json и одобренная IANA гипермедиа на основе JSON application/vnd.collection+json Майка Амундсена.

Представления ошибок HTML

Обычно рендерер ведет себя одинаково независимо от того, имеет ли он дело с обычным ответом или с ответом, вызванным возникшим исключением, например, исключением Http404 или PermissionDenied, или подклассом APIException.

Если вы используете TemplateHTMLRenderer или StaticHTMLRenderer и возникает исключение, поведение немного отличается, и зеркально отражает Django’s default handling of error views.

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

  • Загрузка и рендеринг шаблона с именем {status_code}.html.

  • Загрузка и рендеринг шаблона с именем api_exception.html.

  • Вывод кода статуса HTTP и текста, например, «404 Not Found».

Шаблоны будут отображаться с помощью RequestContext, который включает в себя ключи status_code и details.

Примечание: Если DEBUG=True, то вместо отображения кода статуса HTTP и текста будет отображаться стандартная страница ошибки трассировки Django.


Пакеты сторонних производителей

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

YAML

REST framework YAML обеспечивает поддержку парсинга и рендеринга YAML. Ранее он был включен непосредственно в пакет REST framework, а теперь поддерживается как сторонний пакет.

Установка и настройка

Установите с помощью pip.

$ pip install djangorestframework-yaml

Измените настройки фреймворка REST.

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_yaml.parsers.YAMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_yaml.renderers.YAMLRenderer',
    ],
}

XML

REST Framework XML предоставляет простой неформальный формат XML. Ранее он был включен непосредственно в пакет REST framework, а теперь вместо этого поддерживается как сторонний пакет.

Установка и настройка

Установите с помощью pip.

$ pip install djangorestframework-xml

Измените настройки фреймворка REST.

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework_xml.parsers.XMLParser',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_xml.renderers.XMLRenderer',
    ],
}

JSONP

REST framework JSONP обеспечивает поддержку рендеринга JSONP. Ранее он был включен непосредственно в пакет REST framework, а теперь поддерживается как сторонний пакет.


Предупреждение : Если вам требуются междоменные AJAX-запросы, вам следует использовать более современный подход CORS в качестве альтернативы JSONP. Более подробную информацию смотрите в CORS documentation.

Подход jsonp по сути является взломом браузера, и представляет собой only appropriate for globally readable API endpoints <https://stackoverflow.com/questions/613962/is-jsonp-safe-to-use>`** , где ``GET` запросы являются неаутентифицированными и не требуют никаких разрешений пользователя.


Установка и настройка

Установите с помощью pip.

$ pip install djangorestframework-jsonp

Измените настройки фреймворка REST.

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework_jsonp.renderers.JSONPRenderer',
    ],
}

MessagePack

MessagePack - это быстрый, эффективный формат двоичной сериализации. Juan Riaza поддерживает пакет djangorestframework-msgpack, который обеспечивает поддержку MessagePack renderer и parser для REST framework.

XLSX (конечные точки бинарных электронных таблиц)

XLSX - это самый популярный в мире формат двоичных электронных таблиц. Tim Allen из The Wharton School поддерживает :doc:`drf-renderer-xlsx <https://github.com/wharton/drf-renderer-xlsx>`** , который рендерит конечную точку как электронную таблицу XLSX, используя OpenPyXL, и позволяет клиенту загрузить ее. Электронные таблицы могут быть стилизованы на основе каждого представления.

Установка и настройка

Установите с помощью pip.

$ pip install drf-renderer-xlsx

Измените настройки фреймворка REST.

REST_FRAMEWORK = {
    ...

    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
        'drf_renderer_xlsx.renderers.XLSXRenderer',
    ],
}

Чтобы избежать потоковой передачи файла без имени файла (который браузер часто принимает по умолчанию за файл «download» без расширения), нам нужно использовать миксин для переопределения заголовка Content-Disposition. Если имя файла не указано, то по умолчанию будет использоваться export.xlsx. Например:

from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_renderer_xlsx.mixins import XLSXFileMixin
from drf_renderer_xlsx.renderers import XLSXRenderer

from .models import MyExampleModel
from .serializers import MyExampleSerializer

class MyExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
    queryset = MyExampleModel.objects.all()
    serializer_class = MyExampleSerializer
    renderer_classes = [XLSXRenderer]
    filename = 'my_export.xlsx'

CSV

Значения, разделенные запятыми, - это формат табличных данных в виде обычного текста, который можно легко импортировать в приложения электронных таблиц. Mjumbe Poe поддерживает пакет djangorestframework-csv, который обеспечивает поддержку рендеринга CSV для фреймворка REST.

UltraJSON

UltraJSON - это оптимизированный кодировщик JSON на языке C, который может значительно ускорить рендеринг JSON. Adam Mertz поддерживает :doc:`drf_ujson2 <https://github.com/Amertz08/drf_ujson2>`**, форк ныне не поддерживаемого :doc:`drf-ujson-renderer <https://github.com/gizmag/drf-ujson-renderer>`**, который реализует рендеринг JSON, используя пакет UJSON.

CamelCase JSON

djangorestframework-camel-case предоставляет рендереры и парсеры JSON в верблюжьем регистре для фреймворка REST. Это позволяет сериализаторам использовать имена полей с подчеркиванием в стиле Python, но отображать их в API как имена полей в верблюжьем регистре в стиле Javascript. Поддерживается Vitaly Babiy.

Pandas (CSV, Excel, PNG)

Django REST Pandas предоставляет сериализатор и рендереры, которые поддерживают дополнительную обработку и вывод данных через Pandas DataFrame API. Django REST Pandas включает рендереры для CSV файлов в стиле Pandas, рабочих книг Excel (как .xls, так и .xlsx ), и ряда other formats. Он поддерживается S. Andrew Sheppard как часть wq Project.

LaTeX

Rest Framework Latex предоставляет рендерер, который выводит PDF-файлы с использованием Laulatex. Он поддерживается Pebble (S/F Software).

Вернуться на верх