【一】中间件介绍
- 之前我们通过给视图函数加上装饰器来判断用户是否登录,把没有登陆的用户请求跳转到登录页面。
- 但是如果有很多的功能都需要在登录之后才能使用,那么每个功能对应的视图函数都需要加上装饰器,这样的话就略显繁琐
- 通过django中间件就可以实现控制全局的效果
【1】什么是中间件
- 官方的说法是,中间件是一个用于处理DJango的请求和响应的框架级别的钩子。他是一个轻量,低级别的插件系统,用于在全局范围内改变django的输入和输出。每个中间件组件都负责做一些特别的功能
- 由于它的作用是对全局的影响,所以需要谨慎使用,要不然会影响性能。
- 简单来说,中间件可以定义我们的视图函数在执行之前和执行之后的一些操作,他的本质上是一个自定义类,类中定义了几个方法,Django框架会在请求的特定时间去执行这些方法
- 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',
]
【二】自定义中间件
- 最好现在应用下创建一个文件夹,文件夹下创建py文件,py文件内导入
MiddlewareMixin
类 - 写一个类继承
MiddlewareMixin
类 - django给了我们五个可以自定义的中间件方法
# 可以自定义的方法
# 1.在视图函数接收到请求之前触发
process_request(self,request)
# 2.视图函数被掉哟ing之前触发
process_view(self, request, view_func, view_args, view_kwargs)
# 3.这个方法会在 Django 框架中的视图函数返回一个 TemplateResponse 对象后执行。
process_template_response(self,request,response)
# 4.发生异常后执行
process_exception(self, request, exception)
# 5.响应数据时执行
process_response(self, request, response)
# 必须要掌握的
1.process_request(self,request)
2.process_response(self, request, response)
# 以上的方法返回值可以是None,或者是一个HttpResponse对象,如果是None,就按照原本的规则运行,
# 果如返回了HttpResponse对象,那么直接返回一个页面
【1】process_request
- process_request有一个参数就是request,这个request和视图函数里面的request对象是一样的,在中间件中,在请求达到url之前,可以对这个对象做一系列操作
- 它的返回值可以是一个None,或者是一个HttpResponse对象,如果是None,就正常走到后面的路由视图等,如果是HttpResponse对象,那么直接将这个对象返回到浏览器渲染
- 一下是一些对中间件的研究
多个中间件,Django是如何执行其中的process_request方法的
# 多个中间件,Django是如何执行其中的process_request方法的
# 自定义中间件
class MyMid(MiddlewareMixin):
def process_request(self, request):
print('我是来自第一个中间件的request的消息')
class MyMid2(MiddlewareMixin):
def process_request(self, request):
print('我是来自第二个中间件的request的消息')
# 中间件配置
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',
'app1.mymiddleware.mymid.MyMid',
'app1.mymiddleware.mymid.MyMid2'
]
# 视图函数
def index(request):
print('这是视图函数的index')
return HttpResponse('index')
# 访问index控制台输出结果
我是来自第一个中间件的request的消息
我是来自第二个中间件的request的消息
这是视图函数的index
# 结论
1.中间件的process_request方法是在执行视图函数之前执行的
2.django在执行中间件的process_request方法是按照配置文件从上到下的顺序来的
3.不同中间件之间传递的request是同一个对象
【2】process_response
- 定义process_response方法时,必须要传入两个形参,request和response。
- 这个方法必须要返回response或者HttpResponse对象
- response对象就是django视图函数返回的对象
# 多个中间件,Django是如何执行其中的process_response方法的
# 自定义中间件
class MyMid(MiddlewareMixin):
def process_request(self, request):
print('我是来自第一个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第一个中间件的响应消息')
return response
class MyMid2(MiddlewareMixin):
def process_request(self, request):
print('我是来自第二个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第二个中间件的响应消息')
return response
# 中间件配置
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',
'app1.mymiddleware.mymid.MyMid',
'app1.mymiddleware.mymid.MyMid2'
]
# 视图函数
def index(request):
print('这是视图函数的index')
return HttpResponse('index')
# 访问index控制台输出结果
我是来自第一个中间件的request的消息
我是来自第二个中间件的request的消息
这是视图函数的index
我是来自第二个中间件的响应消息
我是来自第一个中间件的响应消息
# 总结
1.这里返回的resonse对象就是视图函数返回的HttpResponse对象
2.执行的顺序是按照配置列表从下到上执行的
3.不同中间件之间传递的response是同一个对象
【3】processs_view
- 该方法有四个参数process_view(self, request, view_func, view_args, view_kwargs)
- request就是和视图函数的request对象是一样的,
- view_func是Django即将使用的视图函数
- view_args是将要传递给视图函数的位置参数列表
- view_kwargs是将要传递给视图函数的关键字参数字典
- Django在调用视图函数之前回调用process_view方法
- 它应该返回一个None或者一个HttpResponse对象,如果返回None,将继续执行其他中间件的processs_view方法,如果返回HttpResponse对象,Django将不在执行其他的业务逻辑,会直接掉头从配置列表中最后一个中间件的process_response开始依次执行
# 自定义中间件
class MyMid(MiddlewareMixin):
def process_request(self, request):
print('我是来自第一个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第一个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第一个中间件的process_view')
print(view_func, view_func.__name__)
class MyMid2(MiddlewareMixin):
def process_request(self, request):
print('我是来自第二个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第二个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第二个中间件的process_view')
print(view_func, view_func.__name__)
# 控制台输出
我是来自第一个中间件的request的消息
我是来自第二个中间件的request的消息
------------------------------------------
我是来自第一个中间件的process_view
<function index at 0x0000027D5FCA71A0> index
------------------------------------------
我是来自第二个中间件的process_view
<function index at 0x0000027D5FCA71A0> index
这是视图函数的index
我是来自第二个中间件的响应消息
我是来自第一个中间件的响应消息
# 总结
1.process_view方法会在执行process_request方法之后,视图函数之前运行
2.多个中间件的process_view是按照配置文件列表顺序来执行的
【4】process_exception
- 该方法有两个参数,process_exception(self, request, exception)
- 一个是request对象
- 另一个exception是视图函数发生异常而产生的Exception对象
- 这个方法只有在视图函数发生异常了还会执行,他的返回值可以是一个None也可以是一个HttpResponse对象
- 如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并且返回给浏览器。
- 如果返回的是None,那么将默认处理异常
# 自定义中间件
class MyMid(MiddlewareMixin):
def process_request(self, request):
print('我是来自第一个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第一个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第一个中间件的process_view')
print(view_func, view_func.__name__)
def process_exception(self, request, exception):
print(f'中间件1的错误消息:>>>>>>{exception}')
class MyMid2(MiddlewareMixin):
def process_request(self, request):
print('我是来自第二个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第二个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第二个中间件的process_view')
print(view_func, view_func.__name__)
def process_exception(self, request, exception):
print(f'中间件2的错误消息:>>>>>>{exception}')
# 视图函数手动制造错误
def index(request):
print('这是视图函数的index')
asdasdasd
return HttpResponse('index')
# 访问index控制台输出消息
我是来自第一个中间件的request的消息
我是来自第二个中间件的request的消息
------------------------------------------
我是来自第一个中间件的process_view
<function index at 0x000001CACF6F7100> index
------------------------------------------
我是来自第二个中间件的process_view
<function index at 0x000001CACF6F7100> index
这是视图函数的index
中间件2的错误消息:>>>>>>name 'asdasdasd' is not defined
中间件1的错误消息:>>>>>>name 'asdasdasd' is not defined
我是来自第二个中间件的响应消息
我是来自第一个中间件的响应消息
# 总结
1.process_exception方法只有在视图函数抛出异常后才会被调用
2.在抛出异常的前提下,它是在执行完视图函数之后被调用的
3.多个中间件的process_exception方法是配置列表逆序执行的
【5】process_template_response
- 这个方法用的比较少,它有两个参数process_template_response(self, request, response)
- 一个是request对象,另一个是TemplateResponse对象,由视图函数后者中间件产生
- process_template_response实在视图函数执行完成之后立刻执行,但是他有一个条件,那就是视图函数返回的对象有一个render()方法
# 自定义中间件
class MyMid(MiddlewareMixin):
def process_request(self, request):
print('我是来自第一个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第一个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第一个中间件的process_view')
print(view_func, view_func.__name__)
def process_exception(self, request, exception):
print(f'中间件1的错误消息:>>>>>>{exception}')
def process_template_response(self, request, response):
print("MD1 中的process_template_response")
return response
class MyMid2(MiddlewareMixin):
def process_request(self, request):
print('我是来自第二个中间件的request的消息')
def process_response(self, request, response):
print('我是来自第二个中间件的响应消息')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print('------------------------------------------')
print('我是来自第二个中间件的process_view')
print(view_func, view_func.__name__)
def process_exception(self, request, exception):
print(f'中间件2的错误消息:>>>>>>{exception}')
def process_template_response(self, request, response):
print("MD2 中的process_template_response")
return response
# 视图函数
def index(request):
def render():
print('我是视图函数的render')
return HttpResponse('无敌了孩子')
print('这是视图函数的index')
rep = HttpResponse('index')
rep.render = render
return rep
# 控制台输出
我是来自第一个中间件的request的消息
我是来自第二个中间件的request的消息
------------------------------------------
我是来自第一个中间件的process_view
<function index at 0x0000020E5BE967A0> index
------------------------------------------
我是来自第二个中间件的process_view
<function index at 0x0000020E5BE967A0> index
这是视图函数的index
MD2 中的process_template_response
MD1 中的process_template_response
我是视图函数的render
我是来自第二个中间件的响应消息
我是来自第一个中间件的响应消息
【三】中间件执行流程
- 请求到达中间件之后,先按照顺序执行每个中间件的process_request方法
- process_request方法返回值是None就以此执行,如果返回值是HttpResponse对象,那么不在执行后面的process_request方法,而是将这个HttpResponse对象带到当前这个中间件对应的process_response方法,在按照配置列表的逆序执行
- process_request对象都执行完了之后,会进行匹配路由,匹配到路由之后会执行列表第一个中间件的process_view方法,如果所有的中间件的process_view方法返回的都是None,那么将执行对应的视图函数,如果有一个中间件返回了HttpResponse对象,那么将不执行视图函数,之间从列表的最后一个中间件的process_response对象开始执行
- process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下: