DjangoでViewのデコレーターは通常views.pyに書きますが、これをurls.pyに書くようにすると一覧性が高くなるのでお勧めです。
通常の使い方(views.pyでデコレーターを指定)
複数のViewがあって各Viewの実装が大きくなってくると、どのViewにどんなデコレーターが指定されているのかが確認しにくくなってきます。
views.py
def view1(request):
:
# 長〜い処理
:
@login_required
@staff_member_required
def view2(request):
:
# 長〜い処理
:
@login_required
@has_permission('xxx')
def view3(request):
:
# 長〜い処理
:
@login_required
@has_permission('xxx')
def view4(request):
:
# 長〜い処理
:
※説明を簡略化する為、あえて関数ベースViewで書いています。
urls.pyでデコレーターを指定する
urls.pyは基本的にView1つに対して1行のコードを書くだけなので、ここでデコレーターを指定できると一覧性が高そうです。
urls.pyでデコレーターを指定するには次のように書きます。
urls.py
urlpatterns = [
url(r'^$', login_required(has_permission('xxx')(views.view4)))
]
このままだと複数のデコレーターを使用する場合に入れ子になって読みにくいので、デコレータ指定用の関数を作成して使用します。
urls.py
def decorate(view_func, decorators):
for decorator in reversed(decorators):
view_func = decorator(view_func)
urlpatterns = [
url(r'^$', decorete(views.view4, [login_required, has_permission('xxx')]))
]
更に、デコレーターの指定は同じ組み合わせを使うことが多いので、これらのパターンを定数として定義しておきます。
# ログインなしでアクセス可能
PUBLIC = []
# 中の人のみアクセス可能
STAFF_ONLY = [
login_required,
staff_member_required,
]
# 権限xxxを持つ人のみアクセス可能
XXX = [
login_required,
has_permission('xxx'),
]
これで各Viewの指定を確認しやすくすることが出来ました。
urls.py
urlpatterns = [
url(r'^view1/$', decorate(views.view1, PUBLIC)),
url(r'^view2/$', decorate(views.view1, STAFF_ONLY)),
url(r'^view3/$', decorate(views.view2, XXX)),
url(r'^view4/$', decorate(views.view3, XXX)),
]
こんなのもありました
こちらはinclude()に対してもデコレーターを指定できるようです。