web-dev-qa-db-ja.com

Djangoの非グローバルミドルウェア

Djangoには、各リクエストで実行されるミドルウェアを定義する設定ファイルがあります。このミドルウェア設定はグローバルです。ビューごとにミドルウェアのセットを指定する方法はありますか?特定のURLで、グローバルセットとは異なるミドルウェアのセットを使用するようにしたい。

38
hekevintran

あなたが欲しい decorator_from_middleware

from Django.utils.decorators import decorator_from_middleware

@decorator_from_middleware(MyMiddleware)
def view_function(request):
    #blah blah

URLには適用されませんが、ビューごとに機能するため、その効果をきめ細かく制御できます。

45
Ned Batchelder

私はこの問題の本当の解決策を持っています。警告;それはちょっとしたハックです。

""" Allows short-curcuiting of ALL remaining middleware by attaching the
@shortcircuitmiddleware decorator as the TOP LEVEL decorator of a view.

Example settings.py:

MIDDLEWARE_CLASSES = (
    'Django.middleware.common.CommonMiddleware',
    'Django.contrib.sessions.middleware.SessionMiddleware',
    'Django.middleware.csrf.CsrfViewMiddleware',
    'Django.contrib.auth.middleware.AuthenticationMiddleware',
    'Django.contrib.messages.middleware.MessageMiddleware',

    # THIS MIDDLEWARE
    'myapp.middleware.shortcircuit.ShortCircuitMiddleware',

    # SOME OTHER MIDDLE WARE YOU WANT TO SKIP SOMETIMES
    'myapp.middleware.package.MostOfTheTimeMiddleware',

    # MORE MIDDLEWARE YOU WANT TO SKIP SOMETIMES HERE
)

Example view to exclude from MostOfTheTimeMiddleware (and any subsequent):

@shortcircuitmiddleware
def myview(request):
    ...

"""

def shortcircuitmiddleware(f):
    """ view decorator, the sole purpose to is 'rename' the function
    '_shortcircuitmiddleware' """
    def _shortcircuitmiddleware(*args, **kwargs):
        return f(*args, **kwargs)
    return _shortcircuitmiddleware

class ShortCircuitMiddleware(object):
    """ Middleware; looks for a view function named '_shortcircuitmiddleware'
    and short-circuits. Relies on the fact that if you return an HttpResponse
    from a view, it will short-circuit other middleware, see:
    https://docs.djangoproject.com/en/dev/topics/http/middleware/#process-request
     """
    def process_view(self, request, view_func, view_args, view_kwargs):
        if view_func.func_name == "_shortcircuitmiddleware":
            return view_func(request, *view_args, **view_kwargs)
        return None

編集:ビューを2回実行した以前のバージョンを削除しました。

7
Chase Seibert

これは、ネッドの回答へのコメントで提示したシナリオに対処するために最近使用したソリューションです...

それは以下を前提としています:

A)これはカスタムミドルウェア、または独自のミドルウェアクラスで拡張/ラップできるものです

B)ロジックはprocess_viewではなくprocess_requestまで待機できます。これは、process_viewで、解決後にview_funcパラメーターを検査できるためです。 (または、Ignacioによって示されるようにurlresolversを使用するように以下のコードを調整できます)。

# settings.py
EXCLUDE_FROM_MY_MIDDLEWARE = set('myapp.views.view_to_exclude', 
    'myapp.views.another_view_to_exclude')

# some_middleware.py

from Django.conf import settings

def process_view(self, request, view_func, view_args, view_kwargs):
    # Get the view name as a string
    view_name = '.'.join((view_func.__module__, view_func.__name__))

    # If the view name is in our exclusion list, exit early
    exclusion_set = getattr(settings, 'EXCLUDE_FROM_MY_MIDDLEWARE', set())
    if view_name in exclusion_set:
        return None

    # ... middleware as normal ...
    #
    # Here you can also set a flag of some sort on the `request` object
    # if you need to conditionally handle `process_response` as well.

このパターンをさらに一般化する方法があるかもしれませんが、これは私の目標をかなりうまく達成しました。

より一般的な質問に答えるために、Djangoライブラリには、現在これを支援するものは何もないと思います。Djangoユーザーのメーリングリストにとっては良いトピックになるでしょう。まだそこでは取り上げられていません。

5
Joe Holloway

ビュー関数を呼び出す前に呼び出されるprocess_viewメソッドを使用できます。 process_viewで、このビューにこのミドルウェアの傍受が必要かどうかを確認できます。

2
Den Schigrov

私が見つけた最高のことは、if request.path_info.startswith( '...')を使用して、リクエストを返すだけでミドルウェアをスキップすることです。これで、スキップするためだけにミドルウェアを作成し、それを継承することができます。たぶん、もっと簡単なことをして、そのリストをsettings.pyに保存してから、それらをすべてスキップすることができます。私が何らかの形で間違っている場合は、私に知らせてください。

1
dtc

ミドルウェアのラッパーで_request.path_に対して Django.core.urlresolvers.resolve() を使用して、ビューがアプリ内にあるかどうかを確認し、ある場合は処理をスキップします。

これはミドルウェアからビューを除外する簡単な方法だと思います

 from Django.core.urlresolvers import resolve
 current_url = resolve(request.path_info).url_name

 if want to exclude url A,

 class your_middleware:
    def process_request(request):
        if not current_url == 'A':
            "here add your code"
0
Arjun P P

Django rlmiddleware 特定のURLにマップされているビューにのみミドルウェアを適用できます。

0
Jan Wrobel