Django 1.10后的中间件(middleware)使用及升级

前言

Django升级1.10后,中间件有了很大的变化.虽然说给以往版本升级1.10增加了少许工作,但是的确简化了中间件,更容易理解和使用.

Django 1.9及以前的中间件

1.9及以前的中间件只有一种结构,就是新建一个类,在其中按照django文档所述建立几个钩子函数,因为已经是历史了,在这里不多废话,简单写一个例子.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class SimpleMiddleware(object):
# 1.9及以前的middleware
def __init__(self):
pass
def process_request(self, request):
return HttpResponse or None
def process_view(self, request, view_func, view_args, view_kwargs):
return HttpResponse or None
def process_response(self, request, response):
return HttpResponse
def process_template_response(self, request, response):
return HttpResponse
def process_exception(self, request):
return HttpResponse or None
```
## Django 1.10的中间件
1.10后,中间件有两种,一种是和以前一样新建一个类,或者直接新建一个函数.参考[Middleware](https://docs.djangoproject.com/en/1.10/topics/http/middleware/).
1. 方法一
``` python
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# 初始化,仅在启动时调用一次
def __call__(self, request):
# 在调用view前执行的代码,可对request进行操作
response = self.get_response(request)
# 在调用view后执行的代码,在此可对request和response进行操作
return response

  1. 方法二
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def simple_middleware(get_response):
    # 初始化,仅在启动时调用一次
    def middleware(request):
    # 在调用view前执行的代码,可对request进行操作
    response = get_response(request)
    # 在调用view后执行的代码,在此可对request和response进行操作
    return response
    return middleware

可见,相比旧版的构筑方式,新版构筑方式非常简洁和容易理解,但是新版中间件中,只重写了process_requestprocess_response,用__call__替代.其他三种钩子函数依然存在,调用方法也和之前保持一致.但的确平时只用到了这两个钩子函数,只有看文档才能回想起其他那三种的存在.

将之前的中间件升级以适配1.10

方法很简单,参考文档Upgrading pre-Django 1.10-style middleware,其实就是给之前的中间件类一个父类,这个父类会帮助我们进行切换.
很简单的例子:class SimpleMiddleware(object):变为class SimpleMiddleware(MiddlewareMixin):即可,这个转换用的父类路径是django.utils.deprecation.MiddlewareMixin.
它的代码十分简单,看完就能理解新旧中间件的区别.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# django.utils.deprecation.py L126
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

升级中遇到的一些小坑

讲讲我自己升级中碰到的一些小坑

  1. get_response方法
    在新版中间件,这个函数非常重要,Django通过这个函数从request获取response,承上启下,不可或缺.从文档可知,这个函数是在中间件初始化__init__时传入的.但是!!!,在1.10之前的django中,__init__函数并不是每次都能获取到get_response参数,所以会导致报错.
    解决办法就是初始化时给get_response参数一个默认值None,可以参看MiddlewareMixin类的__init__方法.
  2. settings的中间件列表命名
    在之前,settings中的中间件列表是叫MIDDLEWARE_CLASSES的, 然而现在,直接叫做MIDDLEWARE了.如果没注意这一点,依然会各种报错,因为django将你1.10版本的新中间件用1.9的处理方式处理了.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # settings
    # before
    MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    # after
    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',
    ]

结语

虽然说新版本的中间件很简洁很人性化,但是升级过程很蛋疼.不知道在哪看到过,这种开发过程中由于各种原因留下的,后面不得不去修改的,称为’技术债’.
虽然我们主观上不喜欢欠债,但是不可否认贷款是快速发展必经之路.