Django-djangorestframework-渲染模块

目录

  • 渲染模块

    • 渲染模块的效果
    • 源码分析
    • 如何自定义配置使用渲染类
    • 自定义渲染模块

渲染模块

可以根据用户请求 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',  # 这个是给浏览器渲染用的,没有时浏览器渲染会报错
    ],
}
  • 在 settings.py 中配置 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>

原文地址:https://www.cnblogs.com/suwanbin/p/12019289.html

时间: 2024-08-30 18:19:00

Django-djangorestframework-渲染模块的相关文章

django-rest framework 框架生命周期 请求模块 渲染模块 解析模块 异常模块 响应模块

一.DRF框架 1.安装 pip3 install djangorestframework 2.drf框架规矩的封装风格 按功能封装,drf下按不同功能不同文件,使用不同功能导入不同文件 from rest_framework.views import APIView #视图,以后都继承这个,这个也是继承views后一顿操作完善了功能 from rest_framework.response import Response #响应 from rest_framework.request impo

django 自定义分页模块

django 自定义分页模块 from django.shortcuts import render, HttpResponse, redirect from django.utils.safestring import mark_safe class Page(object): def __init__(self, current_page): self.current_page = int(current_page) @property def start(self): return (se

Django的登录模块

Django的登录模块 导入 from django.contrib.auth.decorators import login_required #登录验证装饰器 from django.contrib.auth.models import User from django.contrib import auth #登录 改密 注销一些的相关操作 装饰器 @login_required(login_url='/login/') #装饰器 如果未登录 直接跳转 /login/ def index(

[py][mx]django分页第三方模块django-pure-pagination

分页模块django-pure-pagination - 一款基于django pagination封装的更好用的分页模块 https://github.com/jamespacileo/django-pure-pagination - 安装 pip install django-pure-pagination views.py from pure_pagination import Paginator, EmptyPage, PageNotAnInteger class OrgView(Vie

应用Django构建工作流管理模块(一)

目前基于Django平台的CMS系统很多,Django自带的权限模块可实现简单功能的审批操作,对与复杂流程的审批则无法实现,由于Python语言的强大基因,遂自造轮子,构建了一个工作流管理模块.第一篇先上图,查看效果图. 图1-1 工作流模型定义 图1-2-1 工作流节点定义-基本信息 图1-2-2 工作流节点定义-扩展信息 图1-3 审批历史 图1-4 待办任务 图1-5 审批界面 图1-6 提交确认界面 图1-7 审批成功界面 ok,第一篇先介绍到这里,后面会陆续介绍实现原理.

django form 渲染

Django 的Form 类 Form包含各种字段(Field),每个Field也是一个类,每个Field包含一个widget的类,用来控制html元素的展示个属性等. Form 所有的Form都作为django.forms.Form 的子类创建 form.is_bound 返回当前表单是否已绑定数据 hidden_fields() visible_fields() 分别返回所有隐藏的列和可见的列 Widget 类 每个Field都会根据字段类型对应一个默认的类,也可以手动指定widget的值来

Django分页:使用django.core.paginator模块

#导入模块 from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage #获取使用paginator函数分页集中sql_result,每25条为一页 #sql_result 是元组数据 paginator = Paginator(sql_result, 25) #获取分页的数量 page_sum = paginator.num_pages after_range_num = 3 before_range_num

Django动态渲染多层菜单

为后续给菜单设置权限管理方便,通过给页面模版菜单动态渲染,通过数据菜单表进行匹配需要渲染的菜单 1 #Django表结构 2 3 class Menus(models.Model): 4 5 name = models.CharField(max_length=32, verbose_name=u'菜单名') 6 parent = models.ForeignKey('self', 7 verbose_name=u'父级菜单', 8 null=True, 9 blank=True, 10 def

django 单独测试模块

今天单独测试django的一个views文件,出现错误import的模块没有定义,这个模块是在django项目中自己编写的,解决办法: 1../manage.py shell 通过命令行进去加载,再执行   注意加载时的路径应该是从根目录开始,和./manage.py同级 eg.from apps.test.views import * 2.在当前脚本加载django的环境变量   注:path加载绝对路径   from sys import path   path.append("/.../p

Django 安装MySQLdb模块

首先装 mysql的时候 我用的是 apt-get  install mysql-client-core-5.1  (当时以为core的牛逼)  其实直接安mysql-client-5.1就行了 问题: 运行Django的时候 跟数据库扯上关系的时候就 提示   ImportError: No module named MySQLdb 于是下载  MySQL-python-1.2.3.tat.gz    (下载地址Google下) 解压后 sudo python setup.py build 提