デコレータを使用し、DjangoのViewでGETやPOSTリクエストの処理前後に任意の処理を差し込む方法をまとめます。
やりたいこと
例えば以下のようなViewにおいて、 MyView.get
の処理前に @pre_request
で指定した program1
関数を実行し、
処理後に @post_response
で指定した program2
関数を実行できるようにします。
class MyView(View): @pre_request(program1) @post_response(program2) def get(self, request, *args, **kwargs): ...
デコレータの作成
decorators
モジュールに事前処理を実行するデコレータ pre_request
と事後処理を実行するデコレータ post_response
を実装します。
いずれも実行する関数( program
)を引数にとります。
実のところ特にDjangoの要素はなく、単なるPythonのデコレータです。
from functools import wraps def pre_request(program): """事前処理""" def _decorator(function): @wraps(function) def wrap(self, request, *args, **kwargs): # 引数の関数を実行 program(self, request, *args, **kwargs) # デコレートした関数(getなど)を実行 return function(self, request, *args, **kwargs) return wrap return _decorator def post_response(program): """事後処理""" def _decorator(function): @wraps(function) def wrap(self, request, *args, **kwargs): # デコレートした関数(getなど)を実行 response = function(self, request, *args, **kwargs) # 引数の関数を実行 # HTTPレスポンスも引数に追加 return program(self, request, response, *args, **kwargs) return wrap return _decorator
Viewの実装
あとは decorators
から pre_request
と post_response
をインポートして使うだけです。
from django.views.generic.base import View from .decorators import post_response, pre_request def program1(self, request, *args, **kwargs): """事前処理""" ... def program2(self, request, response, *args, **kwargs): """事後処理""" ... # レスポンスを返すこと return response class MyView(View): @pre_request(program1) @post_response(program2) def get(self, request, *args, **kwargs): ...
利用例
(実用性は無視して)簡単な利用例を挙げておきます。
get()
や post()
の引数を扱えるので、工夫次第で色々できます。
事前処理でビューへのアクセス権限を判定
以下の関数は一般ユーザーのアクセスを拒否します。
この例はあまり実用性がないですが、@permisson_requiredでは対応しきれないような決めの細かい権限管理が必要な場合などに使用できるかもしれません。
from django.core.exceptions import PermissionDenied def do_not_accept_general_user(self, request, *args, **kwargs): """一般ユーザのアクセス拒否""" if not request.user.is_superuser: raise PermissionDenied()
事後処理でレスポンスを更新
事後処理は HttpResponse
を受け取るため、コンテキストの追加変更やレスポンスそのものの上書き(遷移先の変更やURLパラメタの追加など)が可能です。
def update_response(self, request, response, *args, **kwargs): """コンテキストの書き換え""" if something: response.context_data['foo'] = '..' return response
まとめ
デコレータでViewに任意の事前処理、事後処理を差し込む方法をご紹介しました。
Viewに共通する処理をどのように切り出すかは状況に依りますが(CBVの継承やバックエンド、シグナルの実装など)、任意の機能を付け外しできるデコレータは使い方次第で大きな効果を発揮すると思います。