个人理解,中间件就是一个全局装饰器
django middleware 官方文档
如何创建自定义Django中间件 ——by Vitor Freitas
刘江 Django中间件
中间件和装饰器同理,请求的时候从上到下,响应的时候从下向上。就像做手术,先剖开,改造一下,在缝起来。剖开缝合每一层都会消毒干嘛的。哈哈
中间件两种形式,因为 dj 2.2 之后产生 了一个新的方法,可以编写 中间件了。
先看以前老的写法:
process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)
随便在某个 app 下新建一个文件,然后再这个文件里面写 中间件的类就可以了,最后别忘记在settings 的 MIDDLEWARE配置,添加 这个类的路径:
例如在 app 应用下:
在 app 目录下新建一个 py 文件,名字自定义,并在该 py 文件中导入 MiddlewareMixin:
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
pass
settings.py
MIDDLEWARE = [
'app01.middlewares.MD1',
]
中间件的类,可以有 很多函数呀,有几个函数是固定的名字,具体看MiddlewareMixin 的内容
class MiddlewareMixin:
def __init__(self, get_response=None):
self.get_response = get_response
super().__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
下面介绍四个中间件的方法:
- process_request
执行视图函数之前,
process_request 方法有一个参数 request,这个 request 和视图函数中的 request 是一样的
process_request 方法的返回值可以是 None 也可以是 HttpResponse 对象,如果是 None 就继续往下走,否则直接 返回该 HttpResponse 对象,并不会执行视图函数了。
process_request 的时候,如果有返回 HttpResponse 就不会执行视图函数了,直接执行该类下的 process_response 方法返回,其他中间件也不会执行了
- process_response
执行视图函数之后
process_response 方法有两个参数,一个是 request,一个是 response
response 是视图函数返回的 HttpResponse 对象,该方法必须要有返回值,且必须是response
总结一点 ,process_request process_view 都是视图函数之前执行的,如果为 none, 则继续执行其他中间件的,如果为 HttpResponse 对象则就会从跳过视图函数执行 process_response 函数,并且舍弃后面的中间件,执行前面已经有的中间件的 process_response 函数,进行 response 的封装。
因为 process_request process_view 都是相当于 对请求的预处理,发现不合格或其他问题,就不会执行视图函数,相当于过率了这个请求一样的感觉。
- process_view
执行 process_request 之后,视图函数之前
process_view(request, view_func, view_args, view_kwargs)
process_view 方法有四个参数:
request 是 HttpRequest 对象。
view_func 是 Django 即将使用的视图函数。
view_args 是将传递给视图的位置参数的列表。
view_kwargs 是将传递给视图的关键字参数的字典。
view_args 和 view_kwargs 都不包含第一个视图参数(request)
返回:
None、view_func(request) 或 HttpResponse 对象
1、None: 则继续执行下面的中间件 视图函数之前的函数
2、HttpResponse 那就直接返回,和process_response 类似直接执行 上面已经执行的中间件的 process_response 函数
3、view_func(request) 则直接执行视图函数,并且接着执行 本中间件和之前中间件的 process_response 函数
当最后一个中间件的 process_request 到达路由关系映射之后,返回到第一个中间件 process_view,然后依次往下,到达视图函数。
- process_exception
process_exception 方法只有在视图函数中出现异常了才执行
在视图函数之后,在 process_response 方法之前执行
1、process_exception 方法的返回值可以是一个 None (页面报错)也可以是一个 HttpResponse 对象
2、process_exception 方法倒序执行,然后再倒序执行 process_response 方法
总的结构图如果 process_view 方法返回视图函数,提前执行了视图函数,且视图函数报错,则无论 process_exception 方法的返回值是什么,页面都会报错, 且视图函数和 process_exception 方法都不执行
总结以下就是:视图函数执行前的是 process_request, process_view,
视图执行之后的是 process_exception process_response
如果视图执行的前 有了 返回 response 则,直接执行了上面的 process_response,比如 process_request 直接有返回 response ,则会直接 执行当前 和上面 的 process_response。
中间件的新写法:
不再需要继承MiddlewareMixin类。
实际执行结果是一样的。
get_response 方法可能是一个实际视图(如果当前中间件是最后列出的中间件),或者是列表中的下一个中间件
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# 配置和初始化
def __call__(self, request):
# 在这里编写视图和后面的中间件被调用之前需要执行的代码
# 这里其实就是旧的process_request()方法的代码
response = self.get_response(request)
# 在这里编写视图调用后需要执行的代码
# 这里其实就是旧的process_response()方法的代码
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print("Md1在执行%s视图前" %view_func.__name__)
def process_exception(self,request,exception):
print("Md1处理视图异常...")
可以看到新的写法,基于类,不继承 MiddlewareMixin,把 process_request 和 process_response 放到了 实例的 call 方法里面。和 以前的写法是一样的。 个人理解, django 会帮我们把这个类进行封装,让他自动调用 process_view 和 process_exception 等函数的。只要理解执行流程即可
网友评论