Django之中间件

Posted 98wdj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django之中间件相关的知识,希望对你有一定的参考价值。

中间件是什么?

官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

我们一直都在使用中间件,只是没有注意到而已,打开Django项目的Settings.py文件,看到下图的MIDDLEWARE配置项。

#这是默认的7个中间件,总共有7个
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,
]

首先先明确一点,中间件归根结底也只是一个类,既然是类,我们就可以去看看他的方法(为下面自定义类做准备)

随便选择一个,

例如:django.middleware.security.SecurityMiddleware
改写成,from django.middleware.security import SecurityMiddleware
点击SecurityMiddleware,进入他的身体内部

技术图片

你会发现只有三个函数,__init__不用管,初始化函数,主要看process_request,process_response两个函数,其中process_request是请求进来时执行的函数,在路由层之前,process_response是返回响应时执行的函数,在路由层之后。

不懂?(懂的请忽略下图):

技术图片

 

 自定义中间件

知道了中间件的定义,和执行流程,我们就可以自定义中间件了

技术图片

 

上图是默认的中间件之一,那么我们模仿一下,新建一个文件,建个类,改个名字,代码如下:
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
     pass

这样只是一个中间件的模仿,什么用处都没有

由执行顺序可知,process_request和process_response是一个中间件的核心,所以代码如下:

class M1(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第一个中间件的request)

    def process_response(self, request, response):
        print(这是自定义的第一个中间件的response)
        return  response

class M2(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第二个中间件的request)

    def process_response(self, request, response):
        print(这是自定义的第二个中间件的response)
        return response

注意,函数中有response的函数必须返回response

把写好的两个自定义添加到setting的列表中

技术图片

来测试一下

技术图片
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^index/, app01.views.index),
]
urls
技术图片
def index(request):
    print(这是index)

    return HttpResponse(这是index页面)
views

 效果如下:

技术图片

 

所以说,执行顺序是由列表中的顺序决定的,

技术图片

注意:如果你自定义的process_request返回了一个HTTPResponse对象,那么就会有如下结果:

#自定义中间件返回了HTTPResponse对象
class M1(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第一个中间件的request)
        return HttpResponse(这是自定义的第一个中间件的request)
    def process_response(self, request, response):
        print(这是自定义的第一个中间件的response)
        return  response

原本页面:

技术图片

更改中间件之后:

技术图片

后端显示:

技术图片

 

不会执行views里面的函数,相对于请求被拦截,不会执行M2的函数,直接执行该自定义中间件的process_response函数

流程如下:

技术图片

除了process_request和process_response函数,Django还开发其他3个函数(了解即可):

process_view

process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,那么将不会执行Django的视图函数,而是直接在中间件中掉头,倒叙执行一个个process_response方法,最后返回给浏览器

代码如下:

class M1(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第一个中间件的request)
        return HttpResponse(这是自定义的第一个中间件的request)
    def process_response(self, request, response):
        print(这是自定义的第一个中间件的response)
        return  response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("M1 中的process_view")
        print(view_func, view_func.__name__)
class M2(MiddlewareMixin):
def process_request(self, request):
print(‘这是自定义的第二个中间件的request‘)

def process_response(self, request, response):
print(‘这是自定义的第二个中间件的response‘)
return response

def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("M2 中的process_view")
print(view_func, view_func.__name__)

看一下输出结果:

技术图片

process_view方法是在Django路由系统之后,视图系统之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_exception

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

 给代码如下:

class M1(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第一个中间件的request)
        return HttpResponse(这是自定义的第一个中间件的request)
    def process_response(self, request, response):
        print(这是自定义的第一个中间件的response)
        return  response

    def process_exception(self, request, exception):
        print(exception)
        print("M1 中的process_exception")

class M2(MiddlewareMixin):
    def process_request(self, request):
        print(这是自定义的第二个中间件的request)

    def process_response(self, request, response):
        print(这是自定义的第二个中间件的response)
        return response

    def process_exception(self, request, exception):
        print(exception)
        print("M2 中的process_exception")

如果视图函数中无异常,process_exception方法不执行。

想办法,在视图函数中抛出一个异常:

def index(request):
    print("app01 中的 index视图")
    raise ValueError("自定义异常")
    return HttpResponse("O98K")

返回结果为:

技术图片

 

process_template_response(用的比较少)

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

 




以上是关于Django之中间件的主要内容,如果未能解决你的问题,请参考以下文章

Django基础之中间件

Django之权限管理

Django进阶之中间件

django框架之中间件

django之(中间件)middleware

Django之中间件浅析