Suche…


Einführung

Middleware in Django ist ein Framework, mit dem sich Code in die Antwort- / Anforderungsverarbeitung einhaken und die Eingabe oder Ausgabe von Django ändern kann.

Bemerkungen

Die Middleware muss Ihrer Liste mit den Einstellungen von MIDDLEWARE_CLASSES hinzugefügt werden, bevor sie in die Ausführung aufgenommen wird. Die Standardliste, die Django beim Erstellen eines neuen Projekts bereitstellt, lautet wie folgt:

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',
]

Dies sind alle Funktionen, die bei jeder Anforderung der Reihe nach ausgeführt werden (einmal bevor sie Ihren Ansichtscode in views.py und einmal in umgekehrter Reihenfolge für process_response callback (vor Version 1.10) erreichen). Sie führen eine Vielzahl von Dingen aus, beispielsweise das Cross Site Request Forgery (csrf) -Token .

Die Reihenfolge ist wichtig, denn wenn eine Middleware eine Weiterleitung ausführt, wird die gesamte Middleware nie ausgeführt. Wenn eine Middleware erwartet, dass das Csrf-Token vorhanden ist, muss es nach der CsrfViewMiddleware .

Fügen Sie den Anforderungen Daten hinzu

Django macht es sehr einfach, zusätzliche Daten zu Anforderungen für die Verwendung in der Ansicht hinzuzufügen. Zum Beispiel können wir die Unterdomäne aus dem META der Anforderung heraus analysieren und sie als separate Eigenschaft an die Anforderung anhängen, indem Sie Middleware verwenden.

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]

Wenn Sie Ihrer Anfrage Daten mit Middleware hinzufügen, können Sie auf die neu hinzugefügten Daten weiter unten zugreifen. Hier verwenden wir die analysierte Subdomain, um festzustellen, welche Organisation auf Ihre Anwendung zugreift. Dieser Ansatz ist nützlich für Apps, die mit einem DNS-Setup mit Platzhalter-Subdomains bereitgestellt werden, die alle auf eine einzelne Instanz zeigen, und die Person, die auf die App zugreift, möchte eine vom Zugriffspunkt abhängige Version mit Hautfarbe.

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

Denken Sie daran, dass die Reihenfolge wichtig ist, wenn Middleware vorhanden ist. Für Anforderungen möchten Sie, dass die abhängige Middleware nach der Abhängigkeit platziert wird.

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

Middleware zum Filtern nach IP-Adresse

Erstens: Die Pfadstruktur

Wenn Sie es nicht haben, müssen Sie den Middleware- Ordner in Ihrer App mit der folgenden Struktur erstellen:

yourproject/yourapp/middleware

Die Ordner-Middleware sollte sich in demselben Ordner befinden wie Einstellungen.py, URLs, Vorlagen ...

Wichtig: Vergessen Sie nicht, die leere init- Datei im Middleware-Ordner zu erstellen, damit Ihre App diesen Ordner erkennt

Anstatt einen separaten Ordner mit Ihren Middleware-Klassen zu haben, können Sie Ihre Funktionen auch in einer einzigen Datei yourproject/yourapp/middleware.py , yourproject/yourapp/middleware.py .

Zweitens: Erstellen Sie die Middleware

Jetzt sollten wir eine Datei für unsere benutzerdefinierte Middleware erstellen. Angenommen, wir möchten eine Middleware, die die Benutzer anhand ihrer IP-Adresse filtert. Wir erstellen eine Datei mit dem Namen 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

Drittens: Fügen Sie die Middleware in unserem 'settings.py' hinzu.

Wir müssen nach den MIDDLEWARE_CLASSES in der MIDDLEWARE_CLASSES settings.py suchen und dort müssen wir unsere Middleware hinzufügen ( an letzter Stelle hinzufügen). Es sollte so aussehen:

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'
)

Erledigt! Jetzt ruft jede Anfrage jedes Kunden Ihre benutzerdefinierte Middleware auf und verarbeitet Ihren benutzerdefinierten Code!

Ausnahme bei globaler Behandlung

Angenommen, Sie haben eine Logik implementiert, um Versuche zu erkennen, ein Objekt in der Datenbank zu ändern, während der Client, der die Änderungen übermittelt hat, nicht die neuesten Änderungen hatte. In einem solchen Fall ConfictError(detailed_message) Sie eine benutzerdefinierte Ausnahme ConfictError(detailed_message) .

Jetzt möchten Sie einen HTTP 409-Statuscode (Confict) zurückgeben , wenn dieser Fehler auftritt. Sie können dies normalerweise als Middleware verwenden, anstatt sie in jeder Ansicht zu behandeln, die diese Ausnahme auslösen kann.

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)

Den neuen Stil von Django 1.10 Middleware verstehen

Mit Django 1.10 wurde ein neuer Middleware-Stil eingeführt, bei dem process_request und process_response zusammengeführt werden.

In diesem neuen Stil ist eine Middleware eine Callable, die eine andere Callable zurückgibt . Nun, die erstere ist eine Middleware-Fabrik und die letztere ist die eigentliche Middleware .

Die Middleware-Fabrik nimmt als einzige Argumentation die nächste Middleware im Middlewares-Stack oder die Ansicht selbst, wenn der untere Rand des Stacks erreicht ist.

Die Middleware HttpResponse die Anforderung als einzelnes Argument und gibt immer eine HttpResponse .

Das beste Beispiel, um die Funktionsweise von Middleware im neuen Stil zu veranschaulichen, ist wahrscheinlich die Herstellung einer abwärtskompatiblen Middleware :

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow