この記事の内容はミドルウェアとは何かというものです。 PythonでのDjangoミドルウェアの解析は一定の参考値があるので、困っている方は参考にしていただければ幸いです。
公式声明: ミドルウェアは、Django のリクエストと応答を処理するために使用されるフレームワーク レベルのフックです。これは、Django の入力と出力をグローバルに変更するための軽量で低レベルのプラグイン システムです。各ミドルウェア コンポーネントは、いくつかの特定の機能を実行する責任があります。
ただし、世界情勢に影響を与えるため、使用には注意が必要で、不適切に使用するとパフォーマンスに影響を及ぼします。
率直に言うと、ミドルウェアはビュー関数の実行前後にいくつかの追加操作を行うのに役立ちます。これは本質的に、クラス内にいくつかのメソッドが定義されたカスタム クラスです。Django フレームワークはこれらのメソッドを次の場所で実行します。要求された指定された時間。
これまでミドルウェアを使用していましたが、それに気づいていませんでした。Django プロジェクトの Settings.py ファイルを開いて、下の図にある MIDDLEWARE 構成項目を確認してください。
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', ]
MIDDLEWARE 設定項目はリストであり、リストは文字列ですが、これらの文字列が実際にはクラス、つまりミドルウェアです。
次に、ミドルウェア内のメソッドと、それらのメソッドがいつ実行されるかを見てみましょう。
ミドルウェアは、次の 5 つのメソッドを定義できます: (主なものは process_request と process_response)
process_request(self ,request)
ミドルウェアの例をカスタマイズする
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第二个里面的 process_response") return response
戻り値は None または HttpResponse オブジェクトになります。戻り値が None の場合は、通常の処理を続行し、次のミドルウェアに処理を渡します。HttpResponse オブジェクトの場合、Django は view 関数を実行せず、対応するオブジェクトをブラウザに返します。
ミドルウェアが複数ある場合に、Django が process_request メソッドをどのように実行するかを見てみましょう。
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") class MD2(MiddlewareMixin): def process_request(self, request): print("第二个里面的 process_request") pass
上記 2 つのカスタム ミドルウェアを settings.py の MIDDLEWARE 設定項目に登録します。
この時点で、ビューにアクセスすると、ターミナルに次の内容が出力されます。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', 'middlewares.MD1', # 自定义中间件MD1 'middlewares.MD2' # 自定义中间件MD2 ]
第一个里面的 process_request 第二个里面的 process_request app01 中的 index视图
process_response
これには 2 つのパラメータがあり、1 つはリクエスト、もう 1 つはレスポンスです。リクエストは上記の例と同じオブジェクトで、レスポンスはビュー関数によって返される HttpResponse オブジェクトです。このメソッドの戻り値も HttpResponse オブジェクトである必要があります。 process_response メソッドを上記の M1 および M2 に追加します:第二个里面的 process_request 第一个里面的 process_request app01 中的 index视图
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第一个里面的 process_response") return response class MD2(MiddlewareMixin): def process_request(self, request): print("第二个里面的 process_request") pass def process_response(self, request, response): print("第二个里面的 process_response") return response
逆の順序で実行されます。 、最初のもの ミドルウェアの process_request メソッドが最初に実行され、その process_response メソッドが最後に実行されます 最後のミドルウェアの process_request メソッドが最後に実行され、その process_response メソッドが最初に実行されます
process_viewprocess_view(self, request, view_func, view_args, view_kwargs)
request は HttpRequest オブジェクトです。
view_func は、Django が間もなく使用するビュー関数です。 (これは実際の関数オブジェクトであり、文字列としての関数名ではありません。)
view_args是将传递给视图的位置参数的列表.
view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
Django会在调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
给MD1和MD2添加process_view方法:
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第一个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第一个中的process_view") print(view_func, view_func.__name__) class MD2(MiddlewareMixin): def process_request(self, request): print("第二个里面的 process_request") pass def process_response(self, request, response): print("第二个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第二个中的process_view") print(view_func, view_func.__name__)
访问index视图函数,看一下输出结果:
第二个里面的 process_request 第一个里面的 process_request -------------------------------------------------------------------------------- 第二个 中的process_view <function index at 0x000001DE68317488> index -------------------------------------------------------------------------------- 第一个 中的process_view <function index at 0x000001DE68317488> index app01 中的 index视图 第一个里面的 process_response 第二个里面的 process_response
process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
给MD1和MD2添加上这个方法:
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第一个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第一个中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("第一个中的process_exception") class MD2(MiddlewareMixin): def process_request(self, request): print("第二个里面的 process_request") pass def process_response(self, request, response): print("第二个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第二个中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("第二个 中的process_exception")
如果视图函数中无异常,process_exception方法不执行。
想办法,在视图函数中抛出一个异常:
def index(request): print("app01 中的 index视图") raise ValueError("呵呵") return HttpResponse("O98K")
在MD1的process_exception中返回一个响应对象:
class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第一个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第一个中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("第一个中的process_exception") return HttpResponse(str(exception)) # 返回一个响应对象
看输出结果:
第二个里面的 process_request 第一个里面的 process_request -------------------------------------------------------------------------------- 第二个 中的process_view <function index at 0x0000022C09727488> index -------------------------------------------------------------------------------- 第一个 中的process_view <function index at 0x0000022C09727488> index app01 中的 index视图 呵呵 第一个 中的process_exception 第一个里面的 process_response 第二个里面的 process_response
注意,这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。
process_template_response(self, request, response)
它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("第一个里面的 process_request") def process_response(self, request, response): print("第一个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第一个中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("第一个中的process_exception") def process_template_response(self, request, response): print("第一个中的process_template_response") return response class MD2(MiddlewareMixin): def process_request(self, request): print("第二个里面的 process_request") pass def process_response(self, request, response): print("第二个里面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("第二个中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("第二个 中的process_exception") def process_template_response(self, request, response): print("第二个中的process_template_response") return response
views.py中:
def index(request): print("app01 中的 index视图") def render(): print("in index/render") return HttpResponse("O98K") rep = HttpResponse("OK") rep.render = render return rep
访问index视图,终端输出的结果:
第二个里面的 process_request 第一个里面的 process_request -------------------------------------------------------------------------------- 第二个 中的process_view <function index at 0x000001C111B97488> index -------------------------------------------------------------------------------- 第一个 中的process_view <function index at 0x000001C111B97488> index app01 中的 index视图 第一个 中的process_template_response 第二个 中的process_template_response in index/render 第一个里面的 process_response 第二个里面的 process_response
从结果看出:
视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。
上一部分,我们了解了中间件中的5个方法,它们的参数、返回值以及什么时候执行,现在总结一下中间件的执行流程。
请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。
process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。
process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:
附:Django请求流程图
以上がミドルウェアとは何ですか? PythonでのDjangoミドルウェアの解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。