Loading

Django框架之中间件引入

【一】中间件介绍

  • 之前我们通过给视图函数加上装饰器来判断用户是否登录,把没有登陆的用户请求跳转到登录页面。
  • 但是如果有很多的功能都需要在登录之后才能使用,那么每个功能对应的视图函数都需要加上装饰器,这样的话就略显繁琐
  • 通过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方法,在按照配置列表的逆序执行

img

  • process_request对象都执行完了之后,会进行匹配路由,匹配到路由之后会执行列表第一个中间件的process_view方法,如果所有的中间件的process_view方法返回的都是None,那么将执行对应的视图函数,如果有一个中间件返回了HttpResponse对象,那么将不执行视图函数,之间从列表的最后一个中间件的process_response对象开始执行

img

  • process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

img

img

posted @ 2024-03-25 18:04  HuangQiaoqi  阅读(2)  评论(0编辑  收藏  举报