Django中间件

Django 中间件

我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:

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

上图中是Django内部的中间件,这里我们可以看看其源码到底Django的中间件是什么东西:

1.进入中间件的方法:

from django.middleware.csrf import CsrfViewMiddleware   #这里我随便导入下面中间件中的其中一个点击进入该中间件的导入方法(CsrfViewMiddleware)中进一步查看

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',
    'md.middleware.M1',
]

2.查看方法的源码信息:

class CsrfViewMiddleware(MiddlewareMixin):    #源码中该方法是一个类且继承了MiddlewareMixin的方法
    """
    Middleware that requires a present and correct csrfmiddlewaretoken
    for POST requests that have a CSRF cookie, and sets an outgoing
    CSRF cookie.

    This middleware should be used in conjunction with the csrf_token template
    tag.
    """
    # The _accept and _reject methods currently only exist for the sake of the
    # requires_csrf_token decorator.
    def _accept(self, request):
        # Avoid checking the request twice by adding a custom attribute to
        # request.  This will be relevant when both decorator and middleware
        # are used.
        request.csrf_processing_done = True
        return None

3.进入MiddlewareMixin方法中:

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

从MiddlewareMixin的源码中我们可以发现其 是修改 Django request 或者 response 对象的钩子.

在中间件中可以定义四个方法,分别是:

1. process_request(self,request)
2. process_view(self,request,callback,callback_args,callback_kwargs)
3. process_template_response(self,request,response)
4. process_exception(self, request, exception)
5. process_response(self, request, response)

以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

一、process_request&process_response

通过对MiddlewareMixin的源码和Django的内部中间件我们可以自己定义中间件:

1.导入:

方式1:

在csrf.py文件中我们了解了Django的内部中间件的导入方式,所以我们也同样的继承它的方式进行导入

from django.utils.deprecation import MiddlewareMixin

方式2:

因为考虑到方式1的导入方式已经在1.7往后版本中被废弃,所以还有下面这种导入方式,即直接将MiddlewareMixin的源码
粘贴到你当前的py文件中:

class MiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response = get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        if not response:
            response = self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

2.定义中间件class

from django.utils.deprecation import MiddlewareMixin

class M1(MiddlewareMixin): 
    def process_request(self,request):    
        print("m1.process_request")
        
    def process_response(self,request,response):
        print('m1.process_response')
        return response

这里需要注意的是上述代码我们的格式是遵循Django的格式方式进行,即在类中定义两个方法(process_request和process_response)且只有process_response有return值。这里process_respons返回值是必须需要的因为执行过程中在视图的返回的HttpResponse的返回值就就是通过process_respons一层层的进行往上return的,所以process_respons的返回值没有代码则会报错。

3.在setting文件中将我们自定义的中间件进行导入

MIDDLEWARE = [
    'md.middleware.M1',      #自定义中间件写的路径导入
    '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',

]

4.执行过程

下图是正常的一个执行过程,

"D:开发工具PyCharm 5.0.3in
unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
Performing system checks...

System check identified no issues (0 silenced).
September 22, 2017 - 17:32:33
Django version 1.11.4, using settings 'DYA918.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

[22/Sep/2017 17:32:52] "GET /favicon.ico HTTP/1.1" 404 1962

m1.process_request
进入login视图
m1.process_response


[22/Sep/2017 17:33:02] "GET /login.html/ HTTP/1.1" 404 1962

process_request方法进行用户登录验证:

常规的中间件的process_request方法中是没有return方法的,加上return后的执行过程又会是怎样呢:

所以依照这个特性我们就可以在自定义的中间件中定义一个用户登录验证,但是需要注意的是这个自定义的中间件需要放在Django的中间件最后,因为session的中间件在第三个,我们只能放在其之后如下代码:

class M1(MiddlewareMixin):
    def process_request(self,request):  
        if request.path_info == '/login.html':   #这里如果url是login则直接让该请求放下去
            return None
        if not request.session.get('user_info'):  #这里如果其session中未登录则增加return让其重新登录
            return redirect('/login.html')
        
    def process_response(self,request,response):
        print('m1.process_response')

二、process_view

相同的我们也在csrf.py文件中将process_view的继承的方法继承过来:

  • 自定义的中间件:

      class M1(MiddlewareMixin):
          def process_request(self,request):
              print('m1.process_request')
          def process_response(self,request,response):
              print('m1.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              print('m1.process_view')
      class M2(MiddlewareMixin):
          def process_request(self,request):
              print('m2.process_request')
          def process_response(self,request,response):
              print('m2.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              print('m2.process_view')
    
  • 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',
          'md.middleware.M1',
          'md.middleware.M2',
      ]
    
  • 执行的过程

      "D:开发工具PyCharm 5.0.3in
    unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
      Performing system checks...
      
      System check identified no issues (0 silenced).
      September 22, 2017 - 17:32:33
      Django version 1.11.4, using settings 'DYA918.settings'
      Starting development server at http://127.0.0.1:8000/
      Quit the server with CTRL-BREAK.
      [22/Sep/2017 17:32:51] "GET / HTTP/1.1" 200 1716
      
      m1.process_request
      m2.process_request
      m1.process_view
      m2.process_view
      m2.process_response
      m1.process_response
    

通过执行的结果我们可以了解process_view在中间件中的运行过程如下图所示:

当m2.process_view中有return值时

  • 在M1的process_view中使用return值:

      class M1(MiddlewareMixin):
          def process_request(self,request):
              print('m1.process_request')
          def process_response(self,request,response):
              print('m1.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              return HttpResponse("Whatmini")
      class M2(MiddlewareMixin):
          def process_request(self,request):
              print('m2.process_request')
          def process_response(self,request,response):
              print('m2.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              print('m2.process_view')
    
  • 执行结果

      "D:开发工具PyCharm 5.0.3in
    unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
      Performing system checks...
      
      System check identified no issues (0 silenced).
      September 22, 2017 - 17:32:33
      Django version 1.11.4, using settings 'DYA918.settings'
      Starting development server at http://127.0.0.1:8000/
      Quit the server with CTRL-BREAK.
      [22/Sep/2017 17:32:51] "GET / HTTP/1.1" 200 1716
      
      m1.process_request
      m2.process_request
      m1.process_view
      m2.process_response
      m1.process_response
    

这里我们可以知道当某个中间件的process_view中有return值时,其不会再往下去执行下一个中间件的process_view,同时也不会执行视图而是直接执行所有的中间件的process_response的方法,并将该return值返回给客户端

三、porcess_exception

  • 定义中间件

      class M1(MiddlewareMixin):
          def process_request(self,request):
              print('m1.process_request')
          def process_response(self,request,response):
              print('m1.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              return HttpResponse("Whatmini")
      class M2(MiddlewareMixin):
          def process_request(self,request):
              print('m2.process_request')
          def process_response(self,request,response):
              print('m2.process_response')
          def process_view(self,view_func,view_func_args,view_func_kwargs):
              print('m2.process_view')
          def porcess_exception(self,request,exception):
              return HttpResponse("开发的程序员已经被打死")	
    

Django的porcess_exception方法是用来捕捉项目执行过程中的报错信息的,

原文地址:https://www.cnblogs.com/lijian-22huxiaoshan/p/7637595.html