Django中间件开发
Django中间件开发
中间件是一个轻量的、框架级别的插件系统,用来处理Django的请求和响应,在全局范围内改变Django的输入和输出。中间件本质上就是一个自定义类,负责实现一些特定的功能,类中定义了几个方法,Django会在请求的特定的时间去执行这些方法。
Django中间件基本知识
中间件限定在5个方法内写代码,这5个方法的执行顺序也遵循一定的规则,只有准确把握这两点,才能在中间件的开发工作中大大减少出错概率。
中间件配置
要想使用一个中间件,必须把它添加到配置文件settings中
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',
'test_middleware.middlewares.middlewaretest1.middle1',
'test_middleware.middlewares.middlewaretest1.middle2',
]
说明:
没有任何中间件是必须的,在上面的列表可以删除任何中间件,但建议保留CommonMiddleware中间件。
中间件彼此之间可能存在依赖关系,因此列表中的中间件要按照一定顺序排列。
在请求阶段调用视图之前,Django以列表中定义的顺序(自上而下)调用中间件;在处理响应时,调用中间件是倒序,自下而上的。
中间件的方法
-
process_request(self,request)
参数request是一个HttpRequest对象。
Django在执行URL配置之前调用process_request()。这个方法返回None或一个HttpResponse对象。如果返回None,Django继续处理请求,程序向下进行;如果返回一个HttpResponse对象,Django不再向下执行程序,直接返回这个对象。
-
process_view(self,request,view_func,view_args,view_kwargs)
参数request是一个HttpResponse对象;参数view_func是视图函数对象,注意不是视图函数名称的字符串形式;参数view_args是视图函数的位置参数列表;参数view_kwargs是视图函数的关键字参数字典。
process_view()方法在Django调用视图之前调用,这个方法返回None或一个HttpResponse对象。如果返回None,Django继续处理请求,程序向下进行;如果返回一个HttpResponse对象,Django不再向下执行程序,直接返回这个对象。
-
process_template_response(self,request,response)
参数response是一个TemplateResponse对象,由Django视图或其他中间件传递过来。
process_template_response在视图执行完毕后,如果响应实例有render()方法才会被调用。这个方法返回一个实现render()方法的响应对象。因此可以修改传入的response的response.template_name和response,context_data,也可以创建并返回全新的TemplateResponse对象。
该方法很少用到。
-
process_response(self,request,response)
参数request是一个HttpResponse对象;参数response是Django视图或中间件传递过来的HttpResponse对象。
process_response在所有的响应返回给浏览器之前被调用。这个方法返回一个HttpResponse对象。因此可以修改传入的response,或者创建并返回新的HttpResponse对象。
-
process_exception(self,request,exception)
参数request是一个HttpResponse对象;参数exception是一个Exception对象,由视图函数抛出。
process_exception在视图函数抛出异常时被调用。这个方法返回None或一个HttpResponse对象。如果返回HttpResponse对象,会经过响应中间件和模板文件渲染,把得到的响应返回给浏览器。否则使用默认的方法处理异常。
中间件执行流程
在请求阶段调用视图之前,Django会按照MIDDLEWARE中定义的顺序,自上而下应用中间件的两个方法。先自上而下执行每个中间件的process_request()方法,然后自上而下执行每个中间件的process_view()方法。
在响应阶段调用视图之后,中间件会按照MIDDLEWARE中定义的顺序相反的顺序自下而上调用中间件的3个方法,正常情况下,一般自下而上执行每一个中间件的process_response()方法;如果视图出错或抛出异常,自下而上执行每一个中间件的process_exception()方法,然后自下而上执行每一个中间件process_response()方法;如果响应实例有render方法,自下而上执行每一个中间件的process_template_response()方法,然后自下而上执行每一个中间件的的process_response()方法。
样例10: Django中间件编程
URL配置
在test_orm项目中建立一个test_middleware应用并加入settings中,在urls中加入path('test_middleware/',include('test_middleware.urls')),
在应用下新建urls文件并写入:
from django.urls import path
from . import views
urlpatterns = [
# 一个普通视图函数的配置项
path('test/',views.test),
# 能返回包含render方法的对象的视图函数的配置项
path('test2/',views.test2),
]
视图函数
在views中写入两个视图函数,一个是test普通视图函数,另一个是test_temp()函数,主要返回一个对象,这个对象包含render方法,这样可以触发中间件的process_template_response():
from django.shortcuts import render,HttpResponse
# Create your views here.
def test(request):
print('test视图函数运行')
return HttpResponse('hello world!')
class test_temp(object):
def __init__(self,response):
self.response=response
def render(self):
return self.response
def test2(request):
print('test2函数运行,主要为了测试processing_template_response中间件是否运行!!')
resp=HttpResponse('hello world,this is test2')
return test_temp(resp)
在/test_orm/test_middleware/下新建文件夹middlewares,然后在这个文件夹新建文件middlewaretest1.py,在这个文件里新建两个中间件:
from django.utils.deprecation import MiddlewareMixin
class middle1(MiddlewareMixin):
def process_request(self,request):
print('中间件1的processs_request运行,请求URL是:',request.path_info)
def process_response(self,request,response):
print('中间件1的process_response进行响应,状态短语:',response.reason_phrase)
return response
def process_view(self, request, view_func, view_func_args, view_func_kwargs):
print('中间件1的process_view运行')
def process_exception(self,request,exception):
print('中间件1的process_exception运行')
def process_template_response(self, request, response):
print("中间件1的process_template_response运行")
return response
class middle2(MiddlewareMixin):
def process_request(self, request):
print('中间件2的processs_request运行,请求主机IP:{}端口号:{}'.format(request.META.get('REMOTE_ADDR'),request.META.get('SERVER_PORT')))
def process_response(self, request, response):
print('中间件2的process_response进行响应,状态码:',response.status_code)
return response
def process_view(self,request,view_func,view_func_args,view_func_kwargs):
print('中间件2的process_view运行')
def process_exception(self,request,exception):
print('中间件2的process_exception运行')
def process_template_response(self, request, response):
print("中间件2的process_template_response运行")
return response
注册自定义中间价
在settings的MIDDLEWARE中加入
'test_middleware.middlewares.middlewaretest1.middle1',
'test_middleware.middlewares.middlewaretest1.middle2',
测试中间件
启动程序,浏览器输入http://127.0.0.1:8000/test_middleware/test/,当网页正确打开后,可以看到命令行终端显示出中间件方法打印出的信息。
中间件1的processs_request运行,请求URL是: /test_middleware/test/
中间件2的processs_request运行,请求主机IP:127.0.0.1端口号:8000
中间件1的process_view运行
中间件2的process_view运行
test视图函数运行
中间件2的process_response进行响应,状态码: 200
中间件1的process_response进行响应,状态短语: OK
我们把视图函数test中的HttpResponse修改成HttpResponse22,故意形成一个错误,再次运行程序:
中间件1的processs_request运行,请求URL是: /test_middleware/test/
中间件2的processs_request运行,请求主机IP:127.0.0.1端口号:8000
中间件1的process_view运行
中间件2的process_view运行
test视图函数运行
中间件2的process_exception运行
中间件1的process_exception运行
中间件2的process_response进行响应,状态码: 500
中间件1的process_response进行响应,状态短语: Internal Server Error
可以看到视图函数运行错误代码,process_exception()开始运行,最后运行process_response()。
浏览器输入http://127.0.0.1:8000/test_middleware/test2/:
中间件1的processs_request运行,请求URL是: /test_middleware/test2/
中间件2的processs_request运行,请求主机IP:127.0.0.1端口号:8000
中间件1的process_view运行
中间件2的process_view运行
test2函数运行,主要为了测试processing_template_response中间件是否运行!!
中间件2的process_template_response运行
中间件1的process_template_response运行
中间件2的process_response进行响应,状态码: 200
中间件1的process_response进行响应,状态短语: OK