2009-03-29 11 views
5

公開されている(認証されていないユーザーとログインしているユーザーの両方が閲覧できる)ページと、ログインしているユーザーのみが閲覧できるページがあるシステムがあるとします。djangoテンプレートは、呼び出されたビューに@login_requiredデコレータが含まれているかどうかを知ることができますか?

これらの2つのクラスのページごとにテンプレートに少しずつ異なる内容を表示したいとします。 @login_requiredビューデコレータは、ログインしているユーザーだけが表示できるビューで常に使用されます。しかし、私のテンプレートは、このデコレータがテンプレートが呼び出されたビューで使用されているかどうかを知る必要があります。

ユーザーが公開ページ用にログインしているかどうかは気にしないでください。私が気にするのは、一般の人がページを閲覧できるかどうかです。@ login_requiredデコレータがなければ、そのことがわかります。

テンプレートを呼び出すビューに特定のデコレータが使用されているかどうかを、テンプレートがどのように知るかについてのヒントは誰にでも伝えられますか?

答えて

5

はい、可能ですが、それほど簡単ではありません。複雑な要因は、Djangoのlogin_requiredデコレータが実際には2レベルの間接(1つの動的関数と1つの他のデコレータ)を通過し、__call__メソッドを持つクラスであるdjango.contrib.auth.decorators.CheckLoginになります。

のは、あなたがこのようになります非ジャンゴ、ありふれ装飾された機能を持っているとしましょう:fooは、ラップされた関数は、関数オブジェクトの名前をチェックするような単純なことができているかどうかの確認

def my_decorator(func): 
    def inner(): 
     return func() 
    return inner 

@my_decorator 
def foo(): 
    print foo.func_name 

# results in: inner 

。関数内でこれを行うことができます。名前は実際には最後のラッパー関数の名前になります。より複雑な場合は、特に何かを探している場合は、inspectモジュールを使用して現在のフレームから外側のフレームを上に移動することができます。ジャンゴの場合

が、しかし、デコレータは、実際に_CheckLoginクラスのインスタンスであるという事実は、関数が本当に関数ではないので、何のfunc_name性質を持っていないことを意味します。上記のコードをしようとすると例外が発生します。

しかし、django.contrib.auth.decorators._CheckLoginのソースコードを見ると、_CheckLoginインスタンスにはlogin_urlというプロパティがあることがわかります。これは、テストするための非常に簡単なことです。また、他の認証デコレータを実装するために使用される

@login_required 
def my_view(request): 
    is_private = hasattr(my_view, 'login_url') 

_CheckLoginので、このアプローチはまた、permission_requiredのために働くだろう、など私は実際にこれを使用する必要があったことがありませんしかし、1つのビューの周りに複数のデコレータがある場合は、私が実際に探しているものについてコメントすることはできません。読者に残された課題は、フレームスタックを調べることでしょう。

しかし、私は未審査の編集上のアドバイスとして、このようにラップされているかどうかを確認するために関数自体をチェックしてみてください。おそらく、新しい開発者が他のデコレータで叩かれてプロジェクトに来たときに、予想外の動作が起こるのを待っていると思います。実際、djangoフレームワーク自体の変化にも晒されています...セキュリティリスクが発生するのを待っています。

私はVan Galeのアプローチを明示的なものとして推奨しています。そのため、はるかに堅牢な実装です。

+0

あなたの最初のコードブロックは書かれたとおりに動作しません。 my_decoratorは渡された関数を全滅させるので、print文をfooに入れるのは役に立たない。 –

+0

Davidさん、ありがとうございました...私が入力したものを慎重に読まなくても、最初のブロックをめくってメインポイントに到達しました。編集を気に入ってください。 –

+0

詳細な回答ありがとうございます。あなたのエンディングのコメントは、私がやっていることです。私の場合は、 "正しい"方法はあまりにも複雑で堅牢ではないと思います。 –

3

テンプレートに余分なコンテキスト変数を渡します。

ので、@login_requiredたビューはprivate: Trueのように変数を渡すだろうし、他のビューがprivate: False

+0

私は短期間でこれをやりました。 @login_requiredデコレータがなければこの値を導き出すことができるので、完全に効果的ですが、非常に難しくありません。 –

1

を通過するのはなぜあなたのテンプレートは、このことを知っておく必要がありますか? @login_requiredデコレータが使用されている場合、ビュー自体はログインしていない人がページに到達することがないため、テンプレートが最初に表示されることはありません。

+0

おそらく、テンプレートは複数の場所から参照されますが、いくつかのエントリポイントは@login_requiredを持ち、いくつかは入りません。 –

+0

ええ、それは私が仮定したものです。 –

+0

Blairdが正しいです。テンプレートは私のウェブサイトの他のすべてのテンプレートのルート親である私のbase.htmlテンプレートです。 –

0

テンプレートは階層的なので、@login_requiredバージョンと「no @login_required」バージョンはどちらも同じ親から継承されていますか?

これにより、テンプレートの管理が簡単になり、メンテナンスも簡単になります。

+0

微妙な差分があります。私がしたいことと一緒に。特定のテンプレートが使用されているかどうかを確認するために、逆のテンプレート動作を実装しないでください。 –

関連する問題