Django
middle~~POS=TRUNC
Sök…
Introduktion
Middleware i Django är ett ramverk som tillåter kod att ansluta till svar / begäran bearbetning och ändra input eller utgång från Django.
Anmärkningar
Middleware måste läggas till i dina inställningar.py MIDDLEWARE_CLASSES
innan den kommer att inkluderas i körningen. Standardlistan som Django tillhandahåller när du skapar ett nytt projekt är följande:
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',
]
Dessa är alla funktioner som körs i ordning på varje begäran (en gång innan den når din visningskod i views.py
och en gång i omvänd ordning för process_response
återuppringning, före version 1.10). De gör en mängd olika saker som att injicera csrf- symbolen för Cross Site Request Forgery .
Ordningen är viktig eftersom om någon mellanprogramvara omdirigerar, kommer all efterföljande mellanprogram inte att köras. Eller om en middleware förväntar sig att csrf-token är där, måste den köras efter CsrfViewMiddleware
.
Lägg till data i förfrågningar
Django gör det riktigt enkelt att lägga till ytterligare data på begäran om användning i vyn. Vi kan till exempel analysera underdomänet på begäran META och bifoga det som en separat egenskap på begäran med hjälp av mellanprogram.
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]
Om du lägger till data med mellanprogram till din begäran kan du komma åt den nyligen tillagda informationen längre ner i raden. Här använder vi det parsade underdomänet för att bestämma något som vilken organisation som får åtkomst till din applikation. Det här tillvägagångssättet är användbart för appar som distribueras med en DNS-inställning med jokerteckenunderdomäner som alla pekar på en enda instans och personen som öppnar appen vill ha en flådad version beroende på åtkomstpunkten.
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
Kom ihåg att ordningen är viktig när du har mellanprogram beror på varandra. För förfrågningar vill du att det beroende mellanprogrammet ska placeras efter beroendet.
MIDDLEWARE_CLASSES = [
...
'myapp.middleware.SubdomainMiddleware',
'myapp.middleware.OrganizationMiddleware',
...
]
Middleware för att filtrera efter IP-adress
Först: Stigstrukturen
Om du inte har det måste du skapa mellanprogrammappen i din app enligt strukturen:
yourproject/yourapp/middleware
Mappens mellanprogram ska placeras i samma mapp som inställningar.py, webbadresser, mallar ...
Viktigt: Glöm inte att skapa den init .py-tomma filen i mellanprogrammappen så att din app känner igen den här mappen
Istället för att ha en separat mapp som innehåller dina mellanvaruklasser är det också möjligt att lägga dina funktioner i en enda fil, yourproject/yourapp/middleware.py
.
För det andra: Skapa mellanprogrammet
Nu ska vi skapa en fil för vår anpassade mellanprogram. Låt oss i det här exemplet anta att vi vill ha ett mellanprogram som filtrerar användarna baserat på deras IP-adress, vi skapar en fil som heter 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
Tredje: Lägg till mellanprogrammet i våra "inställningar.py"
Vi måste leta efter MIDDLEWARE_CLASSES
inuti settings.py och där måste vi lägga till vårt mellanprogram ( Lägg till det i den sista positionen ). Det borde vara som:
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'
)
Gjort! Nu kommer varje begäran från varje klient att ringa din anpassade mellanprogram och bearbeta din anpassade kod!
Globalt hantering av undantag
Säg att du har implementerat någon logik för att upptäcka försök att modifiera ett objekt i databasen medan klienten som skickade ändringar inte hade de senaste ändringarna. Om ett sådant fall hämtar du ett anpassat undantag ConfictError(detailed_message)
.
Nu vill du returnera en HTTP 409 (Confict) statuskod när detta fel inträffar. Du kan vanligtvis använda som mellanprogram för detta istället för att hantera det i varje vy som kan höja detta undantag.
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)
Förstå Django 1.10 mellanvarans nya stil
Django 1.10 introducerade en ny middleware-stil där process_request
och process_response
slås samman.
I den här nya stilen är en mellanprogramvara en återvinningsbar som returnerar en annan teckningsbar . Tja, faktiskt är den förstnämnda en middleware-fabrik och den senare är den faktiska middleware .
Mellanvarufabriken tar som ett enda argument nästa mellanvaror i mellanvarusbunten eller vyn i sig när bunten av bunten nås.
Mellanprogrammet tar begäran som ett enda argument och returnerar alltid en HttpResponse
.
Det bästa exemplet för att illustrera hur ny stil mellanprogram fungerar är förmodligen att visa hur man gör en bakåtkompatibel mellanprogram :
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