Django 中间件

中间件:

中间件是介于request和response之间的一道处理过程,它在全局上改变了jdango的输入和输出,所以要谨慎使用。它在视图函数执行之前和执行之后做一些额外的操作,本质上是一个自定义类,且定义了几个方法。

django自带的中间件

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',
]

自定义中间件

中间件可以定义5个方法,其中主要是process_request,process_response

process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)

以上方法返回值可以是None,HttpResponse对象,如果是None,则继续按django的规则向后执行,如果是HttpResponse,则直接返回该对象给用户,后面的方法什么的都不会执行。

用户发送请求后会依次经过所有中间件的process_request,然后到达view函数,view函数执行完后,process_response再次穿过中间件,然后返回给请求者。

process_request方法

process_request有一个参数,就是request, 这个request传到视图函数仍叫request,当返回None时,继续执行下一个中间件,如果返回的是HttpResponse对象,,是直接返回给浏览器。

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1里面的 process_request")


class MD2(MiddlewareMixin):

    def process_request(self, request):
        print("MD2里面的 process_request")
        pass

注意:写好中间件后记得注册到setting中

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',
    'middlewares.MD1',
    'middlewares.MD2'
]
# 自定义中间件MD1,这个写的是你项目路径下的一个路径,例如,如果你放在项目下,文件夹名成为utils,那么这里应该写utils.middlewares.MD1

此时访问一个视图函数:会产生下面的结果 :

MD1里面的 process_request
MD2里面的 process_request
app01 中的 index视图

可以看到:

中间件的process_request方法在视图函数之前执行,

顺序按照MIDDLEWARE中注册顺序,从上到下执行。

不同中间件之间传递的对象是同一个对象

process_response

它有两个参数,一个request,一个response。response是视图函数返回的HttpResponse对象。process_response方法返回值必须是HttpResponse对象。

与上面的process_request相反,它是从下往上执行的,

执行流程:

 

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

request, HttpRequest对象

view_func django即将使用的视图函数(函数对象)

view_args 传给视图的位置参数列表

view_kwargs 传递给视图的关键字参数的字典

其中view_args, view_kwargs中都不包含request参数。

process_view会在调用视图函数前调用process_view方法。返回值是一个HttpResponse对象,

流程:

它是在process_request之后 ,视图函数之前执行的。如果其中一个process_view返回了HttpResponse对象,则执行顺序就会改成下面这样:

process_exception(self,request,exception)

request是一个HttpRequest对象

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

此方法只有视图函数中出现异常才会执行,同样只要它返回了HttpResponse对象,后面的流程将被跳过不执行,直接返回给请求用户。

process_template_response(self, request,response)

request是HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)

process_template_response是在视图函数执行冠希民后立即执行,但它有一个前提条件,那是视图函数返回的对象有一个render()方法,

 

应用:

class AuthMD(MiddlewareMixin):
    white_list = ['/login/', ]  # 白名单
    balck_list = ['/black/', ]  # 黑名单

    def process_request(self, request):
        from django.shortcuts import redirect, HttpResponse

        next_url = request.path_info
        print(request.path_info, request.get_full_path())

        if next_url in self.white_list or request.session.get("user"):
            return
        elif next_url in self.balck_list:
            return HttpResponse('This is an illegal URL')
        else:
            return redirect("/login/?next={}".format(next_url))

补充:Django生命周期:

django请求流程图:

 

中间件版的登陆验证:简单的演示下原理

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import reverse, redirect

class Own_Auth(MiddlewareMixin):
    white_list = ['/login/', '/admin/', '/admin/login/', ]

    def process_request(self, request):
        next_url = request.path
        is_login = request.session.get('is_login', None)
        if is_login or next_url in self.white_list:
            return None
        else:
            return redirect(reverse("account:login"))

注意:

中间件写好后要注册到settings的midddleware中。因为process_request会在每个views之前执行,所以一定要加入白名单,否则访问所有的url都会跳转到登陆页面。另外要防止形成递归。

只有返回None时,后面的流程都会继续执行。否则会在此截胡。

 

上一篇:Django 模板渲染的bug

下一篇:Django ORM中的事务和锁X