首页 > 其他分享 >django之中间件(middleware)

django之中间件(middleware)

时间:2023-06-26 18:47:39浏览次数:35  
标签:process 中间件 middleware request django 模块 response

目录

django之中间件(middleware)

在之前一篇博文中,有关django的请求流程中,我们关于中间件这一层并没有详细的介绍,在这张图中,我们将中间层定义为django网关层和路由层的过渡层,那么具体会中间件会做什么事呢。

img

django默认中间件

在配置文件中,有一个MIDDLEWARE列表,里面存放了七个字符串,实际上这就是七个中间件程序,其基础作用就是处理我们的请求和响应,比如第四个中间件就经常妨碍我们发送简单的POST请求,所以初学阶段经常需要将其注释掉不让其生效:

img

这七个中间件程序会在请求来时自上而下依次的处理request请求,在响应走时自下而上依次处理response响应。

django中间件原理

中间件程序结构

这七个字符串实际上对应的是中间件程序存储的路径,我们可以顺着路径进去看一下它们的结构:

img

这七个程序都遵循着这样的结构:

  1. 继承了MiddlewareMixin类

    from django.utils.deprecation import MiddlewareMixin
    
  2. 可能做了一些初始化准备__init__

  3. 拥有process_request和process_response函数

    process_request需要传入request参数,没返回值

    process_response需要传入request和response两个参数,必须返回response

自定义中间件

在知道以上结构后我们可以自己自定义中间件程序:

  1. 首先,我们需要一个py文件存放程序,这个位置最好相对固定

    img

  2. 其次,编写类,导入MiddlewareMixin继承,写好基础的类体函数:
    process_request|process_response
    注意这几个函数具有的特征。

    from django.utils.deprecation import MiddlewareMixin
    
    
    class MidWare01(MiddlewareMixin):
        def process_request(self, request):
            pass
    
        def process_response(self, request, response):
            return response
    
  3. 最后,将编写好的类的路径及类名按格式注册到MIDDLEWARE的列表中。

    img

中间件程序执行顺序

关于process_request和process_response是中间件最常用的函数,我们重点研究这个函数的顺序即可。在自定义中间件中加一点小程序测试一下:

img

当我们从网页向网址发送请求(无论有没有对应路由),后端会打印:

img

我们可以看出一些结论:

  • 请求会经过中间件程序,按注册顺序自上而下的运行每个中间件process_request程序
  • 响应会经过中间件程序,按注册顺序自下而上的运行每个中间件的process_response程序。

我们还可以做进一步的测试,如将process_request设置一个httpResponse返回值和将process_response的response替换成其他响应。

img

直接给出结论:

  • 当中间件的process_request函数返回httpResponse对象,那么就之间去执行当前中间件的process_response函数,这个返回值传入response参数
  • 中间件的process_response的返回值是传递性的,中途可以返回其他的response,返回什么,下一轮的response就接收什么,最终传递给用户浏览器。

我们可以用图解来解释这几个结论:

img

ps:中间件请求函数返回httpResponse对象,在django中是直接执行当前层中间件的process_response,而在flask中,是从最底层的中间件程序的响应函数开始执行的

字符串列表注册原理

如何通过字符串列表来实现中间件程序的注册的,我们需要两个知识点的前置学习:

importlib模块

importlib可以帮助我们用字符串导入模块,拿到一个模块名的字符串,它可以搜索模块,并执行导入操作:

import importlib   # 导入importlib模块

s1 = 'aaa'
res = importlib.import_module(s1)   # 相当于执行import aaa 并将模块名设置为res
res.aaa_attr  # 可以通过res点出aaa模块的属性
s2 = 'pack.md'
ret = importlib.import_module(s2)  # 相当于执行from pack import md 并将模块名设置为ret
ret.md_func()  # 可以通过ret点出md模块的属性方法

import_module方法可以对句点隔开的字符串进行识别,但注意,最终导入的最小单位是py文件,不能导入py文件中的变量

模块对象的反射

在python中一切皆对象,模块也是一种对象,模块的名称空间中的名字就是模块对象的属性。

所以对于一个模块,我们可以通过反射的方式取到其中的类、函数、变量等名字:

import aaa

attr =  getattr(aaa, 'func')  # 寻找aaa模块中的func属性
attr()  # 直接加扩号进行执行

仿django配置文件注册

知道以上两个知识点,我们也可以让仿中间件的注册过程,写好类后,用字符串保存路径,然后顺序执行。核心代码就是将字符串识别成可以执行的类程序:

# MyMiddleWare文件夹midware01.py中
class MidWare01(MiddlewareMixin):
    def process_request(self, request):
        print('from MidWare01 request')
        
# MyMiddleWare文件夹midware02.py中
class MidWare02(MiddlewareMixin):
    def process_request(self, request):
        print('from MidWare01 request')
        
# 注册配置
MIDWARE_LIST = [
    'MyMiddleWare.midware01.MidWare01',
    'MyMiddleWare.midware02.MidWare02',
]

# 按照注册顺序,执行每个类中的process_request方法
import importlib
def all_exec(request):
    for full_path in MIDWARE_LIST:
        # 将字符串切割为模块路径和类名
	    path, cls_name = full_path.rsplit('.', max_split=1) 
        # 通过模块路径字符串拿到模块名
        module_name = importlib.import_module(path)  
        # 通过模块名反射拿到类名
        cls = getattr(module_name, cls_name)  
        # 通过类产生对象
        obj = cls()  
        # 通过对象使用方法
        obj.process_request(request)  # 多态的思想,因为大家的这个功能一致,所以方法名也该一致

自定义中间件

在上一小节已经介绍过自定义中间件的大致方法,这里简单罗列一下:

  1. 首先,我们需要一个py文件存放程序,这个位置最好相对固定
  2. 其次,编写中间件的类,导入MiddlewareMixin继承,写好基础的类体函数
  3. 最后,将编写好的类的路径及类名按格式注册到MIDDLEWARE的列表中。

其中第二步的类体函数,其实对应有很多的中间件方法,这里将会介绍5个中间件方法。

两个常见的自定义方法

process_request

  • 这个方法是用于处理请求的,在网关处理好request之后,路由层处理路由之前,依注册顺序执行。
  • 需要定义request形参接收请求,对请求做一系列判断。
  • 如果process_request返回HttpResponse对象,则不会再执行后续的中间件以及路由等程序,直接将返回值传入process_response。

process_response

  • 这个方法是用于处理响应的,在视图层返回HttpResponse对象的响应后,网关层处理响应之前,由各中间件依注册顺序自下而上执行。
  • 需要定义request、response形参接收请求和响应,对响应做一定的处理。
  • 返回值一定要将response传递走或者返回其他的HttpResponse对象。

三个了解的自定义方法

  1. process_view
    路由匹配成功之后执行视图函数/类之前自动触发(顺序同process_request)
  2. process_exception
    视图函数/类执行报错自动触发(顺序同process_response)
  3. process_template_response
    视图函数/类返回的HttpResponse对象含有render并且对应一个方法的时候自动触发(顺序同process_response)

这三个方法的使用频率十分的低,不过我们需要注意到中间件的职能并不局限于网关和django程序之间了,还有可能是路由与视图层之间,处理错误的时候,视图层与模板层之间。

通过这些我们信息我们也可以绘制一张新的django请求生命流程图。

django请求生命流程图(完整版)

img

标签:process,中间件,middleware,request,django,模块,response
From: https://www.cnblogs.com/wxlxl/p/17506478.html

相关文章

  • django之模板层(templates)
    目录django之模板层(templates)模板语法简介模板语法数据相关{{}}传值和展示值传值的一些特性总结:模板语法过滤器(filters)自定义过滤器(了解)模板语法逻辑相关模板标签(分支、循环)分支标签循环标签给模板变量起别名load加载自定义标签、inclusion_tag(了解)母版的继承(重点)模板的导入(了解)......
  • Django生成MySQL表的字段注释
    https://blog.csdn.net/Tomonkey/article/details/125382817 安装addcommentspipinstalladdcomments给model字段添加verbose_name属性age=models.SmallIntegerField(verbose_name="年龄",blank=True,default=None)settings.py中添加模块INSTALLED_APPS+=[......
  • Django生成MySQL表的字段注释
    1、安装addcommentspipinstalladdcomments2、确认model的verbose_name,如果需要添加注释,需要给字段添加verbose_name属性classStudent(models.Model):name=models.CharField(max_length=200,verbose_name="名称",blank=True,default=None)age=models.SmallInt......
  • django之路由层
    目录django之路由层路由匹配路由匹配小优化转换器转换器种类正则匹配无名分组与有名分组反向解析静态路由的反向解析反向解析语法动态路由的反向解析动态反向解析语法路由分发路由分发后的反向解析django之路由层路由层,主要是路由地址与视图函数的映射关系,如果将网站比作一本......
  • django 环境和安装 + job - 蓝v - django.core.exceptions.ImproperlyConfigured: SQL
    1.部署蓝鲸2.安装djangomkdir~/.virtualenvspython3-mvenv~/.virtualenvs/djangodevpython-mvenv~/.virtualenvs/djangodevsource~/.virtualenvs/djangodev/bin/activatedeactivatesource~/.virtualenvs/djangodev/bin/activatepipinstallDjangopython-c&quo......
  • 生产环境访问django后台,提示CSRF验证失败. 请求被中断
    解决方法:登录后复制 settings.py添加这句代码,域名改为你前端ngx的域名CSRF_TRUSTED_ORIGINS=['https://xxxx.demo.com'] ......
  • 下载中间件实战-Scrapy与Selenium结合
    下载中间件实战-Scrapy与Selenium结合有的页面反爬技术比较高端,一时破解不了,这时我们就是可以考虑使用selenium来降低爬取的难度。问题来了,如何将Scrapy与Selenium结合使用呢?思考的思路: 只是用Selenium来帮助下载数据。因此可以考虑通过下载中间件来处理这块内容。Spider文......
  • Scrapy_下载中间件设置UserAgent
    Scrapy中Downloader设置UA下载中间件是Scrapy请求/响应处理的钩子框架。这是一个轻、低层次的应用。通过可下载中间件,可以处理请求之前和请求之后的数据。如果使用下载中间件需要在Scrapy中的setting.py的配置DOWNLOADER_MIDDLEWARES才可以使用,比如:DOWNLOADER_MIDDLEWARE......
  • django 如何在序列化器中抛出错误 并且在视图中捕捉返回给前端
    1.在create()中抛出错误classYourSerializer(serializers.Serializer):defcreate(self,validated_data):#进行数据验证是否满足条件#得到数据过程以省略condition=Falseifnotcondition:#抛出ValidationError异常,......
  • django 上下文管理器 get_context_data 使用
    在Django中,序列化器(serializer)是用于处理数据的序列化和反序列化的类。而get_context_data()方法是用于获取视图上下文数据的方法。默认情况下,序列化器无法直接拿到get_context_data()中的内容。如果你希望将get_context_data()中的内容传递给序列化器进行处理,可以通过以下几种方......