0

base.html から呼び出されるメソッドで発生させたカスタム例外をキャッチしたいと考えています。それが発生した場合、ユーザーを別のページにリダイレクトする必要があります。これを行うのに最適な場所はどこですか?

以下は、問題を示すコードの簡単な例です

base.html:

{% if something %}{{ widget_provider.get_header }}{% endif %}

widget_providers.py

class SpecificWidgetProvider(BaseWidgetProvider):
    def get_header(self):
        if self.user.is_anonimous():
            raise AuthenticationRequired()
        return third_party_api.get_top_secret_header_widget()

AuthenticationRequired 例外は、サイトの多くの部分で発生する可能性があり (ほとんどの場合ビューで)、ハンドラーを 1 か所に保持したいと考えています。そこで、この種の例外をキャッチするミドルウェアを作成しました。

ミドルウェア.py

def process_exception(request, exception):
    if isinstance(exception, AuthenticationRequired):
        return redirect('accounts:login')

しかし、クラス ベースのビューはテンプレート レンダリング フェーズを後にする可能性があることがわかりました。それらは TemplateResponse インスタンスを返すだけで、Django のリクエスト ハンドラ (django.core.handlers.base の get_response()) は、すべてのミドルウェア スタックの外で response.render() を呼び出します。そのため、ミドルウェアは例外をキャッチできません。コンテキスト プロセッサから get_header() を呼び出すほうがよいかもしれませんが、これも役に立ちません。

4

1 に答える 1

0

同じミドルウェアの process_template_response() で try/except 内のデータをプリフェッチすることで問題を解決し、エラー処理を共通のプライベート メソッドに移動しました。これにより、エラー処理を同じ場所に保持できます。

def process_template_response(self, request, response)
    try:
        widget_provider.get_header()
    except AuthenticationRequired:
        response = self._process_auth_required()
        # Bind render() method that just returns itself, because we must
        # return TemplateResponse or similar here.
        def render(self):
            return self
        response.render = types.MethodType(render, response)
        return response

def process_exception(self, request, exception):
    if isinstance(exception, AuthenticationRequired):
        return self._process_auth_required()

def _process_auth_required(self):
    return redirect('accounts:login')
于 2012-09-10T21:08:59.390 に答える