介绍

在django中,中间件其实就是一个类,在一个请求到来和这个请求结束之前,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下:

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

使用

自定义中间件

  • 创建中间件类

     from django.utils.deprecation import MiddlewareMixin
    
     class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from process_request') def process_view(self, request, callback, callback_args, callback_kwargs): print('from process_view') def process_template_response(self, request, response): print('from process_template_response') def process_exception(self, request, exception): print('from process_exception') def process_response(self, request, response):
    print('from process_response')
    return response

    中间件类

  • 注册中间件

     MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'Middleware.TestMiddleware.Middleware1'
    ]

    settings.py

中间件的钩子函数

中间件提供五个钩子函数供使用,分别是:

  • process_request

    process_request(self,request)
    request:
    process_request有一个参数,就是request,这个request和视图函数中的request是同一个对象。

    我们来看看有多个中间件时,Django是如何执行其中的process_request方法:

     MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware', # 此项便是拦截CSRF请求的中间件
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'Middleware.TestMiddleware.Middleware1'
    'Middleware.TestMiddleware.Middleware2'
    ]

    settings.py

     from django.utils.deprecation import MiddlewareMixin
    
     class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from Middleware1.process_request') class Middleware2(MiddlewareMixin):
    def process_request(self, request): print('from Middleware2.process_request')

    /Middleware/TestMiddleware.py

     from django.shortcuts import render,HttpResponse
    
     def test(request):
    print('from view func')
    return HttpResponse('ok')

    views.py

     from Middleware1.process_request
    from Middleware2.process_request
    from view func

    控制台输出:

    小结:
    1、中间件的process_request方法是在执行视图函数之前执行的。
    2、当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
    3、不同中间件之间传递的request都是同一个对象。
    4、它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而直接将该HttpResponse对象返回给浏览器。
  • process_response

    process_response(self, request, response)
    request:
    HttpRequest对象(请求对象)。
    response:
    response是视图函数返回的HttpResponse对象。

    给上述的Middleware1和Middleware2加上process_response方法:

     from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from Middleware1.process_request') def process_response(self, request, response):
    print('from Middleware1.process_response')
    return HttpResponse('ok') class Middleware2(MiddlewareMixin):
    def process_request(self, request): print('from Middleware2.process_request') def process_response(self, request, response):
    print('from Middleware2.process_response')
    return HttpResponse('ok')

    /Middleware/TestMiddleware.py

    from Middleware1.process_request
    from Middleware2.process_request
    from view func
    from Middleware2.process_response
    from Middleware1.process_response

    控制台输出:

    小结:
    1、process_response方法是在视图函数之后执行的。
    2、多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的。
    3、该方法的返回值必须是HttpResponse对象。
  • process_view

    process_view(self, request, view_func, view_args, view_kwargs)
    request:
    HttpRequest对象(请求对象)。
    view_func:
    请求所对应的视图函数句柄。
    view_args:
    传递给视图函数的位置参数。
    view_kwargs:
    传递给视图函数的关键字参数。

    给上述的Middleware1和Middleware2加上process_view方法:

     from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from Middleware1.process_request') def process_response(self, request, response):
    print('from Middleware1.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view') class Middleware2(MiddlewareMixin):
    def process_request(self, request): print('from Middleware2.process_request') def process_response(self, request, response):
    print('from Middleware2.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view')

    /Middleware/TestMiddleware.py

     from Middleware1.process_request
    from Middleware2.process_request
    from Middleware1.process_view
    from Middleware2.process_view
    from view func
    from Middleware2.process_response
    from Middleware1.process_response

    控制台输出:

    小结:
    1、process_view方法是在process_request之后,视图函数之前执行的。
    2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后顺序执行的。
    3、它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续执行其他中间件的process_view方法,然后再执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用后续的视图函数。 而将直接执行中间件的process_response方法并将用该HttpResponse返回结果。
  • process_exception

    process_exception(self, request, exception)
    request:
    HttpRequest对象(请求对象)。
    exception:
    exception是视图函数产生的Exception(异常)对象。

    修改视图函数,并给上述的Middleware1和Middleware2加上process_exception方法:

     from django.shortcuts import render, HttpResponse
    
     def test(request):
    print('from view func')
    i = 1 / 0
    return HttpResponse('ok')

    views.py

     from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from Middleware1.process_request') def process_response(self, request, response):
    print('from Middleware1.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view') def process_exception(self, request, exception):
    print('from Middleware1.process_exception') class Middleware2(MiddlewareMixin):
    def process_request(self, request): print('from Middleware2.process_request') def process_response(self, request, response):
    print('from Middleware2.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view') def process_exception(self, request, exception):
    print('from Middleware2.process_exception')

    /Middleware/TestMiddleware.py

    from Middleware1.process_request
    from Middleware2.process_request
    from Middleware1.process_view
    from Middleware2.process_view
    from view func
    from Middleware2.process_exception
    from Middleware1.process_exception
    Internal Server Error: ...
    ZeroDivisionError: division by zero
    from Middleware2.process_response
    from Middleware1.process_response

    控制台输出:

    小结:
    1、这个方法只有在视图函数中出现异常了才执行,并且是在process_response之前执行。
    2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后倒序执行的。
    3、它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将在直接依次调用中间件中的process_response方法。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。
  • process_template_response

    process_template_response(self, request, response)
    request:
    HttpRequest对象(请求对象)。
    response:
    response是视图函数返回的HttpResponse对象且这个对象中一定要包含名为render的函数。

    修改视图函数,并给上述的Middleware1和Middleware2加上process_template_response方法:

     from django.shortcuts import render, HttpResponse
    
     def test(request):
    print('from view func')
    def render():
    print('from render')
    resp = HttpResponse('ok')
    resp.render = render
    return resp

    views.py

     from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse class Middleware1(MiddlewareMixin):
    def process_request(self, request): print('from Middleware1.process_request') def process_response(self, request, response):
    print('from Middleware1.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view') def process_exception(self, request, exception):
    print('from Middleware1.process_exception') def process_template_response(self, request, response):
    print('from Middleware1.process_template_response')
    return response class Middleware2(MiddlewareMixin):
    def process_request(self, request): print('from Middleware2.process_request') def process_response(self, request, response):
    print('from Middleware2.process_response')
    return HttpResponse('ok') def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view') def process_exception(self, request, exception):
    print('from Middleware2.process_exception') def process_template_response(self, request, response):
    print('from Middleware2.process_template_response')
    return response

    /Middleware/TestMiddleware.py

    from Middleware1.process_request
    from Middleware2.process_request
    from Middleware1.process_view
    from Middleware2.process_view
    from view func
    from Middleware2.process_template_response
    from Middleware1.process_template_response
    from render
    from Middleware2.process_response
    from Middleware1.process_response

    控制台输出:

    小结:
    1、中间件的process_template_response方法是在执行视图函数之后执行的。而render函数是在process_template_response方法之后process_response方法之前执行的,且仅执行一次。
    2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后倒序执行的。
    3、该方法的返回值必须是HttpResponse对象。

中间件的执行流程

请求到达中间件之后,先按照注册顺序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法。也就是说:如下图,如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4、5、6中间件的process_request和process_response方法都不执行,顺序执行3、2、1中间件的process_response方法。

process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法。如果process_view方法返回None,继续按顺序执行,当所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4、5、6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

python框架之Django(11)-中间件的更多相关文章

  1. python框架之django

    python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django temple django models ...

  2. 第六篇:web之python框架之django

    python框架之django   python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django te ...

  3. Python框架之Django学习

    当前标签: Django   Python框架之Django学习笔记(十四) 尛鱼 2014-10-12 13:55 阅读:173 评论:0     Python框架之Django学习笔记(十三) 尛 ...

  4. Python框架之Django的相册组件

    Python框架之Django的相册组件 恩,没错,又是Django,虽然学习笔记已经结贴,但是学习笔记里都是基础的,Django的东西不管怎么说还是很多的,要学习的东西自然不会仅仅用十几篇博文就能学 ...

  5. Python框架之Django学习笔记(十一)

    话说上次说到数据库的基本访问,而数据库我们主要进行的操作就是CRUD,也即是做计算处理时的增加(Create).读取(Retrieve)(重新得到数据).更新(Update)和删除(Delete),俗 ...

  6. Python高级进阶(二)Python框架之Django写图书管理系统(LMS)

    正式写项目准备前的工作 Django是一个Web框架,我们使用它就是因为它能够把前后端解耦合而且能够与数据库建立ORM,这样,一个Python开发工程师只需要干自己开发的事情就可以了,而在使用之前就我 ...

  7. Python框架下django 的并发和多线程

    django 的并发能力真的是令人担忧,django本身框架下只有一个线程在处理请求,任何一个请求阻塞,就会影响另一个情感求的响应,尤其是涉及到IO操作时,基于框架下开发的视图的响应并没有对应的开启多 ...

  8. Python高级进阶(一)Python框架之Django入门

    传说中的Django Django由来 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下 ...

  9. python框架之Django(1)-第一个Django项目

    准备 自己写一个简单的webServer import socket # 生成socket实例对象 sk = socket.socket() # 绑定IP和端口 sk.bind(("127. ...

随机推荐

  1. 从yield 到yield from再到python协程

    yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...

  2. Atitit 最近资料文章列表r9 r8 月份 attilax总结

    Atitit 最近资料文章列表r9  r8 月份   attilax总结 atitit tag标签标示规范 attilax总结 v2 r922.docx 2017-09-28 02:04 阅读(27) ...

  3. 【将门创投】AI 往期技术分享

    计算机视觉 1. 嘉宾:商汤科技CEO 徐立 文章回顾:计算机视觉的完整链条,从成像到早期视觉再到识别理解 2. 嘉宾:格灵深瞳CTO 赵勇 文章回顾:计算机视觉在安防.交通.机器人.无人车等领域的应 ...

  4. EntityFramework安装失败

    PM> Install-Package EntityFramework正在尝试收集与目标为“.NETFramework,Version=v4.0”的项目“ConsoleApplication1” ...

  5. VBA二次学习笔记(3)——批量合并单元格

    说明(2018-9-16 22:17:49): 1. 昨天运动会,100米八个人跑了第五,400米五个人跑了第三,得了个榨汁机.终于结束了哈哈哈!之前一个星期紧张的天天拉肚子,真是没出息..不过养成了 ...

  6. WPF Button 样式

    WPF CheckBox 自定义样式 给Button设置ToolTip <Style TargetType="{x:Type Button}" x:Key="Def ...

  7. 快速入门 WePY 小程序【转】

    一.WePY介绍 WePY 是 腾讯 参考了Vue 等框架对原生小程序进行再次封装的框架,更贴近于 MVVM 架构模式, 并支持ES6/7的一些新特性. 二.WePY 使用 1.WePY的安装或更新都 ...

  8. python3命令行ImportError: No module named 'xxxx'的问题

    主要原因:启动脚本不在当前目录下,无法找到上一层 在pycharm写好的脚本程序,在命令行无法运行,报错 Traceback (most recent call last): File "t ...

  9. Android打开doc、xlsx、ppt等office文档解决方案

    妹子我写代码很辛苦/(ㄒoㄒ)/~~ ,转载请标明出处哦~http://blog.csdn.net/u011791526/article/details/73088768 1.Android端有什么控 ...

  10. 让织梦内容页arclist标签的当前文章标题加亮显示

    很多人在用织梦做站的时候,会用到在当前栏目页面,给当前栏目标题使用指定样式如标题加亮,或者放个背景图.这是一个很常用和实用的功能,比如在导航页面,标识当前在浏览哪个栏目.如下图: 但是有些时候,我们在 ...