渲染器
在 TemplateResponse 实例可以返回给客户端之前,它必须被渲染。渲染过程采用模板和上下文的中间表示,并将其转换为可以提供给客户端的最终字节流。
REST 框架包含许多内置的 Renderer 类,允许你返回具有各种媒体类型的响应。还支持定义你自己的自定义渲染器,这让你可以灵活地设计自己的媒体类型。
如何确定渲染器
视图的有效渲染器集合始终定义为一个类列表。当进入视图时,REST 框架将在传入请求上执行内容协商,并确定最合适的渲染器来满足请求。
内容协商的基本过程涉及检查请求的 Accept
标头,以确定它在响应中期望哪些媒体类型。或者,URL 上的格式后缀可用于显式请求特定表示形式。例如,URL http://example.com/api/users_count.json
可能是一个始终返回 JSON 数据的端点。
有关更多信息,请参阅 内容协商 文档。
设置渲染器
可以使用 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 框架将选择列表中的第一个呈现器用于响应。
例如,如果你的 API 提供 JSON 响应和 HTML 可浏览 API,你可能希望将 JSONRenderer
设置为默认呈现器,以便向未指定 Accept
头部的客户端发送 JSON
响应。
如果你的 API 包含可以根据请求提供常规网页和 API 响应的视图,那么你可以考虑将 TemplateHTMLRenderer
设置为默认呈现器,以便与发送 损坏的接受头部 的较旧浏览器配合良好。
API 参考
JSONRenderer
使用 utf-8 编码将请求数据呈现为 JSON
。
请注意,默认样式包括 Unicode 字符,并使用紧凑的样式呈现响应,没有不必要的空格
{"unicode black star":"★","value":999}
客户端还可以包含一个 'indent'
媒体类型参数,在这种情况下,返回的 JSON
将缩进。例如 Accept: application/json; indent=4
。
{
"unicode black star": "★",
"value": 999
}
可以使用 UNICODE_JSON
和 COMPACT_JSON
设置键更改默认 JSON 编码样式。
.media_type: application/json
.format: 'json'
.charset: None
TemplateHTMLRenderer
使用 Django 的标准模板呈现将数据呈现为 HTML。与其他呈现器不同,传递给 Response
的数据不需要序列化。此外,与其他呈现器不同,在创建 Response
时,你可能希望包含一个 template_name
参数。
TemplateHTMLRenderer 将创建一个 RequestContext
,使用 response.data
作为上下文词典,并确定用于呈现上下文的模板名称。
注意:当与使用序列化器的视图一起使用时,用于呈现的 Response
可能不是一个字典,在返回之前需要将其包装在一个字典中,以允许 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
通过 REST 框架返回常规 HTML 页面,或者从单个端点返回 HTML 和 API 响应。
如果你正在构建使用 TemplateHTMLRenderer
和其他渲染器类的网站,你应该考虑将 TemplateHTMLRenderer
列为 renderer_classes
列表中的第一个类,以便即使对于发送格式错误的 ACCEPT:
标头的浏览器,它也会优先考虑。
请参阅 HTML 和表单 主题页,了解 TemplateHTMLRenderer
用法的更多示例。
.media_type: text/html
.format: 'html'
.charset: utf-8
另请参阅:StaticHTMLRenderer
StaticHTMLRenderer
一个简单的渲染器,它只返回预渲染的 HTML。与其他渲染器不同,传递给响应对象的数据应为表示要返回的内容的字符串。
使用 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
通过 REST 框架返回常规 HTML 页面,或者从单个端点返回 HTML 和 API 响应。
.media_type: text/html
.format: 'html'
.charset: utf-8
另请参阅:TemplateHTMLRenderer
BrowsableAPIRenderer
为可浏览 API 呈现数据为 HTML
此渲染器将确定哪个其他渲染器将被赋予最高优先级,并使用它在 HTML 页面中显示 API 样式响应。
.media_type: text/html
.format: 'api'
.charset: utf-8
.template: 'rest_framework/api.html'
自定义 BrowsableAPIRenderer
默认情况下,响应内容将使用除 BrowsableAPIRenderer
之外的最高优先级渲染器呈现。如果你需要自定义此行为,例如将 HTML 用作默认返回格式,但在可浏览 API 中使用 JSON,你可以通过覆盖 get_default_renderer()
方法来实现。例如
class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
def get_default_renderer(self, view):
return JSONRenderer()
AdminRenderer
为类似于管理的显示呈现数据为 HTML
此渲染器适用于 CRUD 样式的 Web API,它还应提供一个用户友好的界面来管理数据。
请注意,对于输入具有嵌套或列表序列化程序的视图,它们将无法与 AdminRenderer
很好地配合,因为 HTML 表单无法正确支持它们。
注意:只有当数据中存在正确配置的 URL_FIELD_NAME
(默认值为 url
)属性时,AdminRenderer
才能包含指向详情页面的链接。对于 HyperlinkedModelSerializer
,情况就是这样,但对于 ModelSerializer
或普通 Serializer
类,你需要确保显式包含该字段。例如,这里我们使用模型 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 和表单 文档。
.media_type: text/html
.format:'form'
.charset: utf-8
.template:'rest_framework/horizontal/form.html'
MultiPartRenderer
此呈现器用于呈现 HTML 多部分表单数据。它不适合作为响应呈现器,而是用于创建测试请求,使用 REST 框架的 测试客户端和测试请求工厂。
.media_type:multipart/form-data; boundary=BoUnDaRyStRiNg
.format:'multipart'
.charset: utf-8
自定义渲染器
要实现自定义呈现器,你应覆盖 BaseRenderer
,设置 .media_type
和 .format
属性,并实现 .render(self, data, accepted_media_type=None, renderer_context=None)
方法。
该方法应返回一个字节串,该字节串将用作 HTTP 响应的主体。
传递给 .render()
方法的参数是
数据
请求数据,由 Response()
实例化设置。
accepted_media_type=None
可选。如果提供,这是接受的媒体类型,由内容协商阶段确定。
根据客户端的 Accept:
标头,这可能比呈现器的 media_type
属性更具体,并且可能包括媒体类型参数。例如 "application/json; nested=true"
。
renderer_context=None
可选。如果提供,这是视图提供的上下文信息字典。
默认情况下,这将包括以下键: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, accepted_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, accepted_media_type=None, renderer_context=None):
return data.encode(self.charset)
请注意,如果渲染器类返回 Unicode 字符串,则 Response
类将强制响应内容转换为字节串,并使用渲染器上设置的 charset
属性来确定编码。
如果渲染器返回表示原始二进制内容的字节串,则应设置 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, accepted_media_type=None, renderer_context=None):
return data
高级渲染器用法
您可以使用 REST 框架的渲染器执行一些非常灵活的操作。一些示例...
- 根据请求的媒体类型,从同一端点提供平面或嵌套表示。
- 从同一端点提供常规 HTML 网页和基于 JSON 的 API 响应。
- 为 API 客户端指定多种类型的 HTML 表示。
- 指定渲染器的媒体类型,例如使用
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,则需要更详细地考虑媒体类型的设计和用法。
用 Roy Fielding 的话 说,“REST API 应将几乎所有描述性工作都花在定义用于表示资源和驱动应用程序状态的媒体类型上,或定义现有标准媒体类型的扩展关系名称和/或超文本标记”。
有关自定义媒体类型的良好示例,请参阅 GitHub 使用自定义 application/vnd.github+json 媒体类型,以及 Mike Amundsen 获得 IANA 批准的 application/vnd.collection+json 基于 JSON 的超媒体。
HTML 错误视图
通常,无论渲染器处理的是常规响应还是由异常引起的响应(例如 Http404
或 PermissionDenied
异常或 APIException
的子类),其行为都是相同的。
如果你使用 TemplateHTMLRenderer
或 StaticHTMLRenderer
,并且引发了异常,则行为略有不同,并且反映了 Django 对错误视图的默认处理。
HTML 渲染器引发并处理的异常将尝试按优先顺序使用以下方法之一进行渲染。
- 加载并渲染名为
{status_code}.html
的模板。 - 加载并渲染名为
api_exception.html
的模板。 - 渲染 HTTP 状态代码和文本,例如“404 Not Found”。
模板将使用包含 status_code
和 details
键的 RequestContext
进行渲染。
注意:如果 DEBUG=True
,则将显示 Django 的标准回溯错误页面,而不是渲染 HTTP 状态代码和文本。
第三方包
以下第三方包也可用。
YAML
REST 框架 YAML 提供 YAML 解析和渲染支持。它以前直接包含在 REST 框架包中,现在作为第三方包提供支持。
安装和配置
使用 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 框架 XML 提供简单的非正式 XML 格式。它以前直接包含在 REST 框架包中,现在作为第三方包提供支持。
安装和配置
使用 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 框架 JSONP 提供 JSONP 渲染支持。它以前直接包含在 REST 框架包中,现在作为第三方包提供支持。
警告:如果你需要跨域 AJAX 请求,通常应该使用更现代的 CORS 方法作为 JSONP
的替代方案。有关更多详细信息,请参阅 CORS 文档。
jsonp
方法本质上是一个浏览器黑客,并且 仅适用于全局可读 API 端点,其中 GET
请求未经身份验证且不需要任何用户权限。
安装和配置
使用 pip 安装。
$ pip install djangorestframework-jsonp
修改 REST 框架设置。
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework_jsonp.renderers.JSONPRenderer',
],
}
MessagePack
MessagePack 是一种快速、高效的二进制序列化格式。 Juan Riaza 维护 djangorestframework-msgpack 包,该包为 REST 框架提供 MessagePack 渲染器和解析器支持。
Microsoft Excel:XLSX(二进制电子表格端点)
XLSX 是世界上最流行的二进制电子表格格式。Tim Allen 来自 沃顿商学院,维护 drf-excel,它使用 OpenPyXL 将端点渲染为 XLSX 电子表格,并允许客户端下载它。电子表格可以逐个视图进行样式化。
安装和配置
使用 pip 安装。
$ pip install drf-excel
修改 REST 框架设置。
REST_FRAMEWORK = {
...
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
'drf_excel.renderers.XLSXRenderer',
],
}
为了避免在没有文件名的情况下流式传输文件(浏览器通常会将文件名默认为“下载”,没有扩展名),我们需要使用 mixin 来覆盖 Content-Disposition
头。如果未提供文件名,它将默认为 export.xlsx
。例如
from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_excel.mixins import XLSXFileMixin
from drf_excel.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 包,它为 REST 框架提供 CSV 渲染器支持。
UltraJSON
UltraJSON 是一个经过优化的 C JSON 编码器,可以显著加快 JSON 渲染速度。Adam Mertz 维护 drf_ujson2,它是现在不再维护的 drf-ujson-renderer 的一个分支,它使用 UJSON 包实现 JSON 渲染。
CamelCase JSON
djangorestframework-camel-case 为 REST 框架提供小驼峰式 JSON 渲染器和解析器。这允许序列化程序使用 Python 风格的下划线字段名,但在 API 中以 JavaScript 风格的小驼峰式字段名公开。它由 Vitaly Babiy 维护。
Pandas(CSV、Excel、PNG)
Django REST Pandas 提供一个序列化程序和渲染器,它们通过 Pandas DataFrame API 支持附加数据处理和输出。Django REST Pandas 包含用于 Pandas 风格 CSV 文件、Excel 工作簿(.xls
和 .xlsx
)以及许多 其他格式 的渲染器。它由 S. Andrew Sheppard 作为 wq 项目 的一部分进行维护。
LaTeX
Rest Framework Latex 提供一个使用 Laulatex 输出 PDF 的渲染器。它由 Pebble (S/F Software) 维护。