Zoeken…


Invoering

Middleware in Django is een raamwerk waarmee code kan worden gekoppeld aan de verwerking van antwoorden / verzoeken en de invoer of uitvoer van Django kan wijzigen.

Opmerkingen

Middleware moet worden toegevoegd aan uw instellingen.py MIDDLEWARE_CLASSES lijst voordat het in de uitvoering wordt opgenomen. De standaardlijst die Django biedt bij het maken van een nieuw project is als volgt:

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

Dit zijn allemaal functies die zal lopen met het oog op elk verzoek (een keer voordat het uw uitzicht code bereikt views.py en een keer in omgekeerde volgorde voor process_response terugbellen, voor versie 1.10). Ze doen verschillende dingen, zoals het injecteren van het Cross Site Request Forgery (csrf) -token .

De volgorde is belangrijk, want als sommige middleware een omleiding uitvoert, wordt alle daaropvolgende middleware nooit uitgevoerd. Of als een middleware verwacht dat het csrf-token er is, moet het na de CsrfViewMiddleware .

Voeg gegevens toe aan verzoeken

Django maakt het heel eenvoudig om extra gegevens toe te voegen aan aanvragen voor gebruik binnen de weergave. We kunnen het subdomein bijvoorbeeld ontleden op de META van het verzoek en het als een afzonderlijke eigenschap aan het verzoek koppelen door middel van middleware.

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]

Als u gegevens met middleware aan uw verzoek toevoegt, hebt u later toegang tot die nieuw toegevoegde gegevens. Hier gebruiken we het geparseerde subdomein om zoiets te bepalen als welke organisatie toegang heeft tot uw applicatie. Deze aanpak is handig voor apps die worden geïmplementeerd met een DNS-installatie met wildcard-subdomeinen die allemaal naar één exemplaar verwijzen en de persoon die toegang heeft tot de app wil een gevilde versie afhankelijk van het toegangspunt.

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

Vergeet niet dat volgorde belangrijk is wanneer middleware van elkaar afhankelijk is. Voor verzoeken wilt u dat de afhankelijke middleware achter de afhankelijkheid wordt geplaatst.

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

Middleware om te filteren op IP-adres

Ten eerste: de padstructuur

Als u dit niet hebt, moet u de middleware- map in uw app maken volgens de structuur:

yourproject/yourapp/middleware

De map middleware moet in dezelfde map worden geplaatst als settings.py, urls, templates ...

Belangrijk: vergeet niet het init .py lege bestand in de middleware-map te maken, zodat uw app deze map herkent

In plaats van een aparte map met uw middlewareklassen, is het ook mogelijk om uw functies in één bestand op te nemen, yourproject/yourapp/middleware.py .

Ten tweede: maak de middleware

Nu moeten we een bestand maken voor onze aangepaste middleware. Laten we in dit voorbeeld veronderstellen dat we een middleware willen die de gebruikers filtert op basis van hun IP-adres, we maken een bestand met de naam 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

Derde: voeg de middleware toe in onze 'settings.py'

We moeten zoeken naar de MIDDLEWARE_CLASSES in de settings.py en daar moeten we onze middleware toevoegen ( voeg deze in de laatste positie toe ). Het zou moeten zijn als:

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

Gedaan! Nu roept elk verzoek van elke klant uw aangepaste middleware op en verwerkt uw aangepaste code!

Wereldwijd afhandelingsuitzondering

Stel dat u enige logica hebt geïmplementeerd om pogingen om een object in de database te wijzigen te detecteren, terwijl de client die de wijzigingen heeft ingediend niet over de laatste wijzigingen beschikte. Als een dergelijk geval gebeurt, ConfictError(detailed_message) u een aangepaste uitzondering ConfictError(detailed_message) .

Nu wilt u een HTTP 409-statuscode (Confict) retourneren wanneer deze fout optreedt. U kunt dit meestal als middleware gebruiken in plaats van het af te handelen in elke weergave die deze uitzondering zou kunnen veroorzaken.

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)

De nieuwe stijl van Django 1.10 middleware begrijpen

Django 1.10 introduceerde een nieuwe middleware-stijl waarbij process_request en process_response worden samengevoegd.

In deze nieuwe stijl is een middleware een opvraagbaar dat een ander opvraagbaar retourneert . Nou, eigenlijk is de eerste een middleware-fabriek en de laatste is de eigenlijke middleware .

De middleware-fabriek neemt als enkel argument de volgende middleware in de middlewares-stapel, of de weergave zelf wanneer de onderkant van de stapel wordt bereikt.

De middleware neemt het verzoek op als één argument en retourneert altijd een HttpResponse .

Het beste voorbeeld om te illustreren hoe nieuwe middleware werkt, is waarschijnlijk om te laten zien hoe een achterwaarts compatibele middleware te maken :

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow