django中间件

Django中间件

(1)介绍

  • django中间件是django的门户

    • 请求来的时候需要经过中间件才能到达真正的django后端
    • 响应走的时候最后也需要经过中间件才能发送出去
  • django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法

    • process_request
    • process_response
    • process_view
    • process_template_response
    • process_exception

(2)如何自定义中间件

  • 在项目名或者应用名下创建一个任意名称的文件夹
  • 在该文件夹内创建一个任意名称的py文件
  • 在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
    • 然后再这个类里面就可以自定义五个方法了
    • (这五个方法并不是全部都需要书写,用几个书写几个)
  • 需要将类的路径以字符串的形式注册到配置文件中才能生效
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',
    '自己写的中间件的路径'
]

(3)process_request

  • 请求来的时候需要经过每一个中间件里面的process_request方法
  • 结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
  • 如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
  • 如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行,而是原路返回(检验失败不允许访问...)
  • process_request方法就是用来做全局相关的所有限制功能
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'cbv.mymiddleware.mydd.MyMiddleware'
    'cbv.mymiddleware.mydd.MyMiddleware2'
]
from django.shortcuts import HttpResponse,render,redirect
from django.utils.deprecation import MiddlewareMixin


class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个自定义中间件里面的process_request方法')
        return HttpResponse('我是第一个自定义中间件里面的process_request方法返回的数据')


class MyMiddleware2(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二个自定义中间件里面的process_request方法')
        return HttpResponse('我是第二个自定义中间件里面的process_request方法返回的数据')

image

(4)process_response

  • 响应走的时候需要经过每一个中间件里面的process_response方法
    • 该方法有两个额外的参数request,response
  • 该方法必须返回一个HttpResponse对象
    • 默认返回的就是形参response
    • 也可以返回自己的
  • 顺序是按照配置文件中注册了的中间件从下往上依次经过
    • 如果没有定义的话 直接跳过执行下一个
from django.shortcuts import HttpResponse, render, redirect
from django.utils.deprecation import MiddlewareMixin


class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个自定义中间件里面的process_request方法')
        return

    def process_response(self, request, response):
        """

        :param request:
        :param response: 就是django后端返回给浏览器的内容
        :return:
        """
        print('我是第一个自定义中间件里面的process_response方法')
        return response

class MyMiddleware2(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二个自定义中间件里面的process_request方法')
        return HttpResponse('我是第二个自定义中间件里面的process_request方法返回的数据')

    def process_response(self, request, response):
        print('我是第二个自定义中间件里面的process_response方法')
        return response
# 我是第一个自定义中间件里面的process_request方法
# 我是第二个自定义中间件里面的process_request方法

# 我是第二个自定义中间件里面的process_response方法
# 我是第一个自定义中间件里面的process_response方法

image

image

总结:

​ process_request方法是从上往下执行

​ process_response方法是从下往上执行

  • 如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是会直接走同级别的process_response返回
from django.shortcuts import HttpResponse, render, redirect
from django.utils.deprecation import MiddlewareMixin


class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个自定义中间件里面的process_request方法')
        return HttpResponse('我是第一个自定义中间件里面的process_request方法返回的数据')

    def process_response(self, request, response):
        """

        :param request:
        :param response: 就是django后端返回给浏览器的内容
        :return:
        """
        print('我是第一个自定义中间件里面的process_response方法')
        return response
        # 我是第一个自定义中间件里面的process_request方法
        # 我是第一个自定义中间件里面的process_response方法

class MyMiddleware2(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二个自定义中间件里面的process_request方法')
        return HttpResponse('我是第二个自定义中间件里面的process_request方法返回的数据')

    def process_response(self, request, response):
        print('我是第二个自定义中间件里面的process_response方法')
        return response

image

(5)process_view

  • 路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该方法
  • 顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
def process_view(self, request, view_name, *args, **kwargs):
    print(view_name, args, kwargs)
    print('我是第一个自定义中间件里面的process_view方法')

(6)process_template_response

  • 返回的HttpResponse对象有render属性的时候才会触发
  • 顺序是按照配置文件中注册了的中间件从下往上执行
def process_template_response(self, request, response):
    print('我是第一个自定义中间件里面的process_template_response方法')
    return response
def index(request):
    print('我是视图函数的index')
    obj= HttpResponse('index')
    def render():
        print('我是render')
        return HttpResponse('render')
    obj.render = render
    return HttpResponse('index')

(7)process_exception

  • 当视图函数中出现异常的情况下触发
  • 顺序是按照配置文件中注册了的中间件从下往上执行
def process_exception(self, request, exception):
    print('我是第一个自定义中间件里面的process_exception方法')
    print(exception)

Django中间件编程思想

(1)定义包

def wechat(content):
    print(f"wechat的通知:>>>{content}")


def QQ(content):
    print(f"QQ的通知:>>>{content}")


def email(content):
    print(f"email的通知:>>>{content}")

(2)启动文件中启动包

  • start
from send_message import *


def send_all(content):
    wechat(content=content)
    QQ(content=content)
    email(content=content)


if __name__ == '__main__':
    send_all("test")
wechat的通知:>>>test
QQ的通知:>>>test
email的通知:>>>test

(3)升级版

  • 先分别创建不同的消息功能文件
    • 在同一个文件夹下
    • 创建三个功能文件
class WeChat(object):
    def __init__(self):
        # 发送微信消息前的准备工作
        pass

    def send(self, content):
        print(f"WeChat的消息 :>>>{content}")
class QQ(object):
    def __init__(self):
        # 发送QQ消息前的准备工作
        pass

    def send(self, content):
        print(f"QQ的消息 :>>>{content}")
class Email(object):
    def __init__(self):
        # 发送邮箱消息前的准备工作
        pass

    def send(self, content):
        print(f"email的消息 :>>>{content}")
  • 在上面的文件内创建初始化文件
import settings
import importlib

def send_all(content):
    # 拿到每一个包的路径
    for path_str in settings.MODEL_LIST:
        model_path, class_name = path_str.rsplit('.', maxsplit=1)
        # model_path : model.email
        # class_name : Email
        # (1)利用字符串导入模块
        # models : 模块对象
        models = importlib.import_module(model_path)
        # (2)利用反射拿到类名
        cls = getattr(models, class_name)
        # (3)生成类的对象
        obj = cls()
        # (4)利用鸭子类型直接调用send发送消息
        obj.send(content)


if __name__ == '__main__':
    send_all('1')
  • 在外部定义一个配置文件 settings
MODEL_LIST = [
    'model.email.Email',
    'model.QQ.QQ',
    'model.WeChat.WeChat',
]
  • 在外部真正功能文件
import model

model.send_all('test')
email的消息 :>>> test
QQ的消息 :>>> test
WeChat的消息 :>>> test

遵从Python中的鸭子类型

可以在功能文件中自定义功能文件添加或者注释

settings.py 文件中相关的路径注释掉或添加上去即可

posted @ 2024-03-29 09:57  ALPACINO6  阅读(31)  评论(0)    收藏  举报