Django中间件

余生颓废 提交于 2020-01-15 21:53:18

Django中间件

中间件介绍

中间件就是用来处理Django的请求和响应的框架级别钩子,用于全局范围内改变Django的输入和输出,说直白一点,就是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定时间去执行这些方法。

它就是Django的"门户,保安"

只要是全局相关的功能都可以考虑使用Django中间件来完成

  • 全局用户身份校验
  • 全局用户访问频率校验
  • 用户访问黑名单
  • 用户访问白名单

Settings.py文件中,以下这些就是中间件

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声明周期图中的位置和作用

Django还支持自定义中间件


自定义中间件

也就是说我们可以自己控制"保安"的个数

中间件可以定义五个方法,分别是:(主要的是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

process_request有一个参数,就是request,这个request和视图函数中的request是一样的(在交给Django后面的路由之前,对这个request对象可以进行一系列的操作)

from django.utils.deprecation import MiddlewareMixin

class MyMd1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')

class MyMd2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

在settings.py中需要注册上自定义的中间件

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',
    'MyMIDDLEMARE.MyMDD.MyMd1', # 自定义的中间件
    'MyMIDDLEMARE.MyMDD.MyMd2', # 自定义的中间件
]

访问结果如下

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
我是视图函数index

请求来的时候会按照配置文件中注册的中间件从上往下的顺序依次执行每一个中间件里面的process_request方法,如果没有直接跳过执行下一个

process_response

响应走的时候会按照配置文件中注册的中间件从下往上的顺序依次执行每一个中间件里面的process_response方法,该方法必须要有两个形参,并且需要将形参response返回,如果内部定义了返回了HttpResponse对象,会将返回给用户浏览器的内容替换成HttpResponse对象

from django.utils.deprecation import MiddlewareMixin

class MyMd1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')
        # return HttpResponse("我是第一个中间件返回的HttpResponse对象")

    def process_response(self,request,response):
        print('我是第一个中间件里面的process_response方法')
        return response  # 就是后端返回给前端浏览器的响应数据

class MyMd2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第二个中间件里面的process_response方法')
        return response

访问结果如下

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
我是视图函数index
我是第二个中间件里面的process_response方法
我是第一个中间件里面的process_response方法

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法最先执行

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)
from django.utils.deprecation import MiddlewareMixin

class MyMd1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')
        # return HttpResponse("我是第一个中间件返回的HttpResponse对象")

    def process_response(self,request,response):
        print('我是第一个中间件里面的process_response方法')
        return response  # 就是后端返回给前端浏览器的响应数据

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第一个中间件里面的process_view方法')

class MyMd2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第二个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第二个中间件里面的process_view方法')

访问结果如下

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
我是第一个中间件里面的process_view方法
我是第二个中间件里面的process_view方法
我是视图函数index
我是第二个中间件里面的process_response方法
我是第一个中间件里面的process_response方法

该方法在路由匹配成功执行视图函数之前触发,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_template_response

process_template_response(self,request,response)

该方法有两个参数,一个HttpRequest对象,response是emplateResponse对象

from django.utils.deprecation import MiddlewareMixin

class MyMd1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')
        # return HttpResponse("我是第一个中间件返回的HttpResponse对象")

    def process_response(self,request,response):
        print('我是第一个中间件里面的process_response方法')
        return response  # 就是后端返回给前端浏览器的响应数据

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第一个中间件里面的process_view方法')

    def process_template_response(self,request,response):
        print('我是第一个中间件里面的process_template_response方法')
        return response

class MyMd2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第二个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第二个中间件里面的process_view方法')

    def process_template_response(self,request,response):
        print('我是第二个中间件里面的process_template_response方法')
        return response

views.py

def index(request):
    print('我是视图函数index')
    def render():
        return HttpResponse('我是index里面的render函数')
    obj = HttpResponse('index')
    obj.render = render
    return obj

访问结果如下

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
我是第一个中间件里面的process_view方法
我是第二个中间件里面的process_view方法
我是视图函数index
我是第二个中间件里面的process_template_response方法
我是第一个中间件里面的process_template_response方法
我是第二个中间件里面的process_response方法
我是第一个中间件里面的process_response方法

该方法在视图函数执行完成后,且返回的对象中必须要有render属性对应的render方法时触发,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

process_exception

该方法有两个参数

process_exception(self, request, exception)

  • 一个是HttpRequest对象
  • 一个exception是视图函数异常产生的Exception对象
from django.utils.deprecation import MiddlewareMixin

class MyMd1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义中间件里面的process_request方法')
        # return HttpResponse("我是第一个中间件返回的HttpResponse对象")

    def process_response(self,request,response):
        print('我是第一个中间件里面的process_response方法')
        return response  # 就是后端返回给前端浏览器的响应数据

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第一个中间件里面的process_view方法')

    def process_template_response(self,request,response):
        print('我是第一个中间件里面的process_template_response方法')
        return response

    def process_exception(self, request, exception):
        print('exception', exception)
        print('我是第一个中间件里面的process_exception方法')

class MyMd2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第二个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第二个中间件里面的process_view方法')

    def process_template_response(self,request,response):
        print('我是第二个中间件里面的process_template_response方法')
        return response

    def process_exception(self, request, exception):
        print('exception', exception)
        print('我是第二个中间件里面的process_exception方法')

views.py

def index(request):
    print('我是视图函数index')
    dsadsa
    def render():
        return HttpResponse('我是index里面的render函数')
    obj = HttpResponse('index')
    obj.render = render
    return obj

访问结果

我是第一个自定义中间件里面的process_request方法
我是第二个自定义中间件里面的process_request方法
我是第一个中间件里面的process_view方法
我是第二个中间件里面的process_view方法
我是视图函数index
exception name 'dsadsa' is not defined
我是第二个中间件里面的process_exception方法
exception name 'dsadsa' is not defined
我是第一个中间件里面的process_exception方法
我是第二个中间件里面的process_response方法
我是第一个中间件里面的process_response方法

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象,它的执行顺序也是按照中间件注册顺序的倒序执行

注意:这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。


中间件的流程图

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!