Django: ミドルウェアの実装方法(全てのビューに処理をフックする方法)

2010年3月25日

Djangoでは、アプリ、context_processorsなど様々なプラグイン機能が提供されており、画一的なフレームワークの中でソフトウェアを実装することで効率化・高可搬性を実現しています。 しかし、一旦システムを実装開始すると、システムは様々な環境が依存しあうもので、一つの関数を書き換えると様々なビューやテンプレートファイルに修正範囲が波及する。。。なんてことがよく起こります。 

せっかくMVCフレームワークを提供しているのに、それを正しく使わないのが悪い!などと怒られそうですが、理想と現実は異なる訳で、プラットフォームにはそのどちらもフォローできる柔軟な環境が求められます。 

既存のシステム全てに共通で処理をフックしたり、テンプレート変数を追加したい。。。などということを実現するにはどうしたら良いのでしょうか? これを簡単に実現できる方法がDjangoにはあります。 それが「ミドルウェア」です。

ミドルウェアは大まかに言うと、「ビューをコールする直前と直後にフックを入れることができる機能」です。従って、全てのビューにある特定のテンプレート変数を追加・変更したり、共通の処理を追加することが可能です。 ミドルウェアを追加する場合、 

  1. ミドルウェアクラスを新規作成 
  2. ミドルウェアクラスをsettings.pyに登録 
といった手順を経る必要があります。 まずはsettings.pyにミドルウェアを登録しましょう。 

$ emacs settings.py 

... 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
MIDDLEWARE_CLASSES = ( ..., 'hoge_app.middlewares.hookfunc', )  

# 次に、実態 hookfunc クラスを実装します。 

$ emacs hoge_app/middlewares.py 

class hookfunc(): 
    def __init__(self): 
        pass 

    def process_request(self, request): 
         """ 
        どのviewを実行するか決定する前にコールされるフック。 
         """ 
         return request
         # ここで処理終了 

    def process_view(self, request, view_func, view_args, view_kwargs): 
        """ 
        実行されるviewが決定した後にコールされるフック。 
        """ 
        return response
        # ここで処理終了 

    def process_response(self, request, response): 
         """ 
         viewを実行した後に呼びだされるフック。
         """ 
         return response
         # ここで処理終了

ミドルウェアクラスでは、予めI/Fとして定義されている 


  • process_request(self, request)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_response(self, request, response) 

をオーバーライドすることで、実行されるタイミングが決定されます。

また、返り値としてNoneを返すと次のミドルウェアクラスのハンドラを実行し、 requestオブジェクトやresponseオブジェクトを返すと、そこで処理が完了するといった処理を実現することも可能です。