Рендереры¶
Прежде чем экземпляр 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}
Имя шаблона определяется (в порядке предпочтения):
Явный аргумент
template_name
, передаваемый в ответ.Явный набор атрибутов
.template_name
для этого класса.Возвращаемый результат вызова
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:
Этот рендерер определяет, какой другой рендерер имел бы наивысший приоритет, и использует его для отображения ответа в стиле 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 для отображения в стиле администратора:
Этот рендерер подходит для веб-интерфейсов в стиле 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).