サーチ…


前書き

Djangoのミドルウェアは、コードが応答/要求処理にフックして、Djangoの入力または出力を変更するためのフレームワークです。

備考

実行に含める前に、ミドルウェアをsettings.py MIDDLEWARE_CLASSESリストに追加する必要があります。 Djangoが新しいプロジェクトを作成するときに提供するデフォルトのリストは次のとおりです:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

これらはすべて、すべてのリクエスト( views.pyビューコードに達する前とprocess_responseコールバックの逆順、バージョン1.10より前)に順番に実行されるすべての関数です。 クロスサイトリクエスト偽造(csrf)トークンを注入するなど、さまざまなことを行います。

何らかのミドルウェアがリダイレクトを行うと、その後のすべてのミドルウェアが決して実行されないため、順序は重要です。また、ミドルウェアがcsrfトークンがそこにあることを期待している場合は、CsrfViewミドルウェアの後に実行するCsrfViewMiddlewareます。

リクエストにデータを追加する

Djangoでは、ビュー内での使用のために、追加のデータをリクエストに追加するのがとても簡単です。たとえば、リクエストのMETAのサブドメインを解析し、ミドルウェアを使用して要求の別のプロパティとしてアタッチすることができます。

class SubdomainMiddleware:
    def process_request(self, request):
        """
        Parse out the subdomain from the request
        """
        host = request.META.get('HTTP_HOST', '')
        host_s = host.replace('www.', '').split('.')
        request.subdomain = None
        if len(host_s) > 2:
            request.subdomain = host_s[0]

ミドルウェアを使用してデータをリクエストに追加すると、新しく追加されたデータにさらにアクセスすることができます。ここでは、解析されたサブドメインを使用して、組織がアプリケーションにアクセスしているようなものを判断します。このアプローチは、すべてのインスタンスが1つのインスタンスを指しているワイルドカードサブドメインを持つDNS設定で展開され、アプリケーションにアクセスするユーザーがアクセスポイントに依存するスキンバージョンを必要とする場合に便利です。

class OrganizationMiddleware:
    def process_request(self, request):
        """
        Determine the organization based on the subdomain
        """
        try:
            request.org = Organization.objects.get(domain=request.subdomain)
        except Organization.DoesNotExist:
            request.org = None

ミドルウェアをお互いに依存させる場合は、順序が重要であることに注意してください。リクエストの場合、依存するミドルウェアを依存関係の後に置くことが望ましいでしょう。

MIDDLEWARE_CLASSES = [
    ...
    'myapp.middleware.SubdomainMiddleware',
    'myapp.middleware.OrganizationMiddleware',
    ...
]

IPアドレスでフィルタリングするミドルウェア

最初:パス構造

あなたがそれを持っていない場合は、構造内の次のアプリケーション内にミドルウェアフォルダを作成する必要があります:

yourproject/yourapp/middleware

フォルダミドルウェアは、settings.py、urls、templates ...と同じフォルダに配置する必要があります。

重要:アプリケーションがこのフォルダを認識できるように、ミドルウェアフォルダ内にinit .pyファイルを作成することを忘れないでください

ミドルウェアクラスを含む別個のフォルダを持つ代わりに、あなたの関数を1つのファイル、 yourproject/yourapp/middleware.pyに入れることも可能yourproject/yourapp/middleware.py

Second:ミドルウェアを作成する

これでカスタムミドルウェアのファイルを作成する必要があります。この例では、ユーザのIPアドレスに基づいてユーザをフィルタするミドルウェアが必要であると仮定して、 filter_ip_middleware.pyというファイルを作成します。

#yourproject/yourapp/middleware/filter_ip_middleware.py
from django.core.exceptions import PermissionDenied    

class FilterIPMiddleware(object):
    # Check if client IP address is allowed
    def process_request(self, request):
        allowed_ips = ['192.168.1.1', '123.123.123.123', etc...] # Authorized ip's
        ip = request.META.get('REMOTE_ADDR') # Get client IP address
        if ip not in allowed_ips:
            raise PermissionDenied # If user is not allowed raise Error

       # If IP address is allowed we don't do anything
       return None

3番目:ミドルウェアを 'settings.py'に追加する

settings.pyの中でMIDDLEWARE_CLASSESを探し、ミドルウェアを追加する必要があります( 最後の位置に追加してください )。それは次のようにすべきです:

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',
     # Above are Django standard middlewares

     # Now we add here our custom middleware
     'yourapp.middleware.filter_ip_middleware.FilterIPMiddleware'
)

完了!すべてのクライアントからのすべてのリクエストがカスタムミドルウェアを呼び出し、カスタムコードを処理します。

グローバルに処理する例外

変更を送信したクライアントに最新の変更がないときに、データベース内のオブジェクトを変更しようとする試みを検出するロジックを実装したとします。そのような場合は、カスタム例外ConfictError(detailed_message)ます。

このエラーが発生したときに、 HTTP 409(Confict)ステータスコードを返すようにします 。通常、この例外を発生させる可能性のある各ビューではなく、ミドルウェアとしてこれを処理します。

class ConfictErrorHandlingMiddleware:
    def process_exception(self, request, exception):
        if not isinstance(exception, ConflictError):
            return  # Propagate other exceptions, we only handle ConflictError
        context = dict(confict_details=str(exception))
        return TemplateResponse(request, '409.html', context, status=409)

Django 1.10ミドルウェアの新しいスタイルを理解する

Django 1.10では、 process_requestprocess_responseがマージされた新しいミドルウェアスタイルが導入されました。

この新しいスタイルでは、ミドルウェアは別の呼び出し可能コードを返す呼び出し可能コードです。実際、 前者はミドルウェアファクトリであり、後者は実際のミドルウェアです

ミドルウェア・ファクトリは、ミドルウェア・スタック内の次のミドルウェア 、またはスタックの一番下に達するとビュー自体を単一の引数として取ります。

ミドルウェアは要求を単一の引数として受け取り、 常にHttpResponse返します

新しいスタイルのミドルウェアがどのように機能するかを示す最も良い例は、おそらく下位互換性のあるミドルウェアを作成する方法を示すことです

class MyMiddleware:

    def __init__(self, next_layer=None):
        """We allow next_layer to be None because old-style middlewares
        won't accept any argument.
        """
        self.get_response = next_layer

    def process_request(self, request):
        """Let's handle old-style request processing here, as usual."""
        # Do something with request
        # Probably return None
        # Or return an HttpResponse in some cases

    def process_response(self, request, response):
        """Let's handle old-style response processing here, as usual."""
        # Do something with response, possibly using request.
        return response

    def __call__(self, request):
        """Handle new-style middleware here."""
        response = self.process_request(request)
        if response is None:
            # If process_request returned None, we must call the next middleware or
            # the view. Note that here, we are sure that self.get_response is not
            # None because this method is executed only in new-style middlewares.
            response = self.get_response(request)
        response = self.process_response(request, response)
        return response


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow