可以根据用户请求 URL 或 用户可接受的类型,筛选出合适的 渲染组件。 reponse 数据 json 与 browser 两种渲染方式 浏览器 和 Postman 请求结果渲染数据的方式不一样
# 内置渲染器
# 可以根据用户请求 URL 或 用户可接受的类型,筛选出合适的 渲染组件。
# 显示json格式:JSONRenderer
http://127.0.0.1:8000/test/?format=json
http://127.0.0.1:8000/test.json
# 默认显示格式:BrowsableAPIRenderer(可以修改它的html文件)
http://127.0.0.1:8000/test/?format=admin
http://127.0.0.1:8000/test.admin
# 表格方式:AdminRenderer
http://127.0.0.1:8000/test/?format=form
http://127.0.0.1:8000/test.form
# form表单方式:HTMLFormRenderer
http://127.0.0.1:8000/test/?format=form
http://127.0.0.1:8000/test.form
postman 测试
浏览器渲染
未提供浏览器渲染时
入口 dispatch 中的 self.response = self.finalize_response(request, response, *args, **kwargs)
rest_framework.views.APIView#dispatch
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 请求模块
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
# 渲染模块 -- drf 渲染模块入口
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
rest_framework.views.APIView#finalize_response
def finalize_response(self, request, response, *args, **kwargs):
"""
Returns the final response object.
"""
# Make the error obvious if a proper response is not returned
assert isinstance(response, HttpResponseBase), (
'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
'to be returned from the view, but received a `%s`'
% type(response)
)
if isinstance(response, Response):
if not getattr(request, 'accepted_renderer', None):
# 获得解析类 (从这里再进入)
neg = self.perform_content_negotiation(request, force=True)
request.accepted_renderer, request.accepted_media_type = neg
response.accepted_renderer = request.accepted_renderer
response.accepted_media_type = request.accepted_media_type
response.renderer_context = self.get_renderer_context()
# Add new vary headers to the response instead of overwriting.
vary_headers = self.headers.pop('Vary', None)
if vary_headers is not None:
patch_vary_headers(response, cc_delim_re.split(vary_headers))
for key, value in self.headers.items():
response[key] = value
return response
rest_framework.views.APIView#perform_content_negotiation
def perform_content_negotiation(self, request, force=False):
"""
Determine which renderer and media type to use render the response.
"""
# 后去渲染类(从这里再进入)
renderers = self.get_renderers()
# 得到的就是渲染类的对象
conneg = self.get_content_negotiator()
try:
return conneg.select_renderer(request, renderers, self.format_kwarg)
# 在根据 request 请求的方式再选择具体是选择哪种渲染方式,然后再调用某个方法,把数据渲染成 页面 或 json
except Exception:
if force:
return (renderers[0], renderers[0].media_type)
raise
rest_framework.views.APIView#get_renderers
def get_renderers(self):
"""
Instantiates and returns the list of renderers that this view can use.
"""
# self.renderer_classes,当前类对象没有该属性,去找类,在类属性中找到了
return [renderer() for renderer in self.renderer_classes]
# self.renderer_classes 遍历出来是两个渲染类,类加括号会调用类的 __init__ 方法实例化
self.renderer_classes
来源
class APIView(View):
# self.renderer_classes 取到的即是配置中的 DEFAULT_RENDERER_CLASSES
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
E:/python3-6-4/Lib/site-packages/rest_framework/settings.py
分析 settings 源码
"""
Settings for REST framework are all namespaced in the REST_FRAMEWORK setting.
For example your project's `settings.py` file might look like this:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer',
],
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
}
This module provides the `api_setting` object, that is used to access
REST framework settings, checking for user settings first, then falling
back to the defaults.
"""
from django.conf import settings
from django.test.signals import setting_changed
from django.utils.module_loading import import_string
from rest_framework import ISO_8601
DEFAULTS = {
# Base API policies
'DEFAULT_RENDERER_CLASSES': [
# 默认提供了这两种渲染方式
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
# ...
}
# ...
得知我们可以在自己的 settings 文件中这样来配置它的解析类(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [ # 全局配置的解析方式,所有视图类都会受这个影响
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer', # 这个是给浏览器渲染用的,没有时浏览器渲染会报错
],
}
DEFAULT_RENDERER_CLASSES
完成的是全局配置,所有接口统一处理# 写成类属性就可以变成局部配置了
from rest_framework.renders import JSONRenderer
class Test2(APIView):
renderer_classes = [JSONRenderer,] # 必须是以一个可迭代类型(for ... 遍历它了)
def get(self, request, *args, **kwargs):
return Response("drf get ok 2")
def post(self, request, *args, **kwargs):
return Response("drf post ok 2")
查找顺序:自定义视图类(局部) => APIView 视图类 => 自定义 drf 配置(全局) => drf 默认配置
视图类
from rest_framework.renderers import TemplateHTMLRenderer
class BookDetailView(APIView):
renderer_classes = [TemplateHTMLRenderer]
def get(self,request,pk):
book_obj = models.Book.objects.filter(pk=pk).first()
bs = BookSerializers(book_obj,many=False)
return Response(bs.data,template_name='aa.html')
aa.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
</head>
<body>
{{ title }}
{{ publishDate }}
</body>
</html>