Middleware¶
Middleware är ett ramverk av hooks i Djangos request/response-behandling. Det är ett lätt ”plugin”-system på låg nivå för att globalt ändra Djangos in- eller utdata.
Varje middleware-komponent är ansvarig för att utföra en specifik funktion. Till exempel innehåller Django en middleware-komponent, AuthenticationMiddleware, som associerar användare med förfrågningar med hjälp av sessioner.
Detta dokument förklarar hur middleware fungerar, hur du aktiverar middleware och hur du skriver din egen middleware. Django levereras med några inbyggda middleware som du kan använda direkt ur lådan. De är dokumenterade i inbyggd middleware-referens.
Skriva din egen middleware¶
En middleware-fabrik är en callable som tar en get_response callable och returnerar en middleware. En middleware är en anropsbar som tar emot en begäran och returnerar ett svar, precis som en vy.
En middleware kan skrivas som en funktion som ser ut så här:
def simple_middleware(get_response):
    # One-time configuration and initialization.
    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        response = get_response(request)
        # Code to be executed for each request/response after
        # the view is called.
        return response
    return middleware
Eller så kan det skrivas som en klass vars instanser är anropsbara, så här:
class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.
    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        response = self.get_response(request)
        # Code to be executed for each request/response after
        # the view is called.
        return response
Den get_response callable som tillhandahålls av Django kan vara den faktiska vyn (om detta är den sista listade middleware) eller det kan vara nästa middleware i kedjan. Den aktuella mellanvaran behöver inte veta eller bry sig om exakt vad den är, bara att den representerar vad som kommer härnäst.
Ovanstående är en liten förenkling - den anropbara get_response för den sista middlewaren i kedjan kommer inte att vara den faktiska vyn utan snarare en omslagsmetod från hanteraren som tar hand om att tillämpa view middleware, anropa vyn med lämpliga URL-argument och tillämpa template-response och exception middleware.
Middleware kan antingen stödja endast synkrona Python (standard), endast asynkrona Python, eller båda. Se Asynkront stöd för detaljer om hur man annonserar vad man stödjer, och vet vilken typ av förfrågan man får.
Middleware kan finnas var som helst på din Python-väg.
__init__(get_response)¶
Middleware-fabriker måste acceptera ett get_response-argument. Du kan också initiera ett globalt tillstånd för mellanvaran. Tänk på ett par försiktighetsåtgärder:
- Django initierar din middleware med endast - get_responseargumentet, så du kan inte definiera- __init__()som kräver några andra argument.
- Till skillnad från metoden - __call__()som anropas en gång per förfrågan, anropas- __init__()bara en gång, när webbservern startar.
Markera middleware som oanvänd¶
Det är ibland användbart att vid uppstart avgöra om en del av middleware ska användas. I dessa fall kan din middlewares __init__() metod ge upphov till MiddlewareNotUsed. Django kommer då att ta bort den middleware från middleware-processen och logga ett debug-meddelande till loggern django.begäran när DEBUG är True.
Aktivering av middleware¶
För att aktivera en middleware-komponent lägger du till den i listan MIDDLEWARE i dina Django-inställningar.
I MIDDLEWARE representeras varje middleware-komponent av en sträng: den fullständiga Python-sökvägen till middleware-fabrikens klass- eller funktionsnamn. Här är till exempel standardvärdet som skapades av django-admin startproject:
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]
En Django-installation kräver inte någon middleware - MIDDLEWARE kan vara tom om du vill - men det rekommenderas starkt att du åtminstone använder CommonMiddleware.
Ordningen i MIDDLEWARE är viktig eftersom ett mellanprogram kan vara beroende av andra mellanprogram. Till exempel lagrar AuthenticationMiddleware den autentiserade användaren i sessionen; därför måste den köras efter SessionMiddleware. Se Beställning av mellanprogramvara för några vanliga tips om ordning av Django middleware-klasser.
Ordning och skiktning av mellanprogram¶
Under förfrågningsfasen, innan vyn anropas, tillämpar Django middleware i den ordning som definieras i MIDDLEWARE, uppifrån och ner.
Du kan tänka på det som en lök: varje middleware-klass är ett ”lager” som omsluter vyn, som finns i lökens kärna. Om begäran passerar genom alla lager i löken (varje lager anropar get_response för att skicka begäran till nästa lager), hela vägen till vyn i kärnan, kommer svaret sedan att passera genom varje lager (i omvänd ordning) på väg tillbaka ut.
Om ett av lagren bestämmer sig för att kortsluta och returnera ett svar utan att någonsin anropa sitt get_response, kommer inget av lagren i löken inuti det lagret (inklusive vyn) att se begäran eller svaret. Svaret kommer bara att returneras genom samma lager som begäran passerade in genom.
Andra middleware-hooks¶
Förutom det grundläggande request/response-mönstret för middleware som beskrivits tidigare kan du lägga till tre andra specialmetoder till klassbaserade middleware:
process_view()¶
- process_view(request, view_func, view_args, view_kwargs)¶
request är ett HttpRequest objekt. view_func är den Python-funktion som Django ska använda. (Det är det faktiska funktionsobjektet, inte namnet på funktionen som en sträng.) view_args är en lista över positionella argument som kommer att skickas till vyn, och view_kwargs är en ordbok över nyckelordsargument som kommer att skickas till vyn. Varken view_args eller view_kwargs inkluderar det första vyargumentet (request).
process_view() anropas precis innan Django anropar vyn.
Det bör returnera antingen None eller ett HttpResponse-objekt. Om det returnerar None kommer Django att fortsätta bearbeta denna begäran, köra alla andra process_view() middleware och sedan den lämpliga vyn. Om det returnerar ett HttpResponse-objekt kommer Django inte att bry sig om att anropa lämplig vy; det kommer att tillämpa svarsmellanprogram till det HttpResponse och returnera resultatet.
Observera
Åtkomst till request.POST inuti middleware innan vyn körs eller i process_view() kommer att förhindra att en vy som körs efter middleware kan modifiera uppladdningshanterarna för begäran, och bör normalt undvikas.
Klassen CsrfViewMiddleware kan betraktas som ett undantag, eftersom den tillhandahåller dekoratorerna csrf_exempt() och csrf_protect() som gör det möjligt för vyer att uttryckligen styra vid vilken tidpunkt CSRF-valideringen ska ske.
process_exception()¶
- process_exception(request, exception)¶
request är ett HttpRequest objekt. exception är ett Exception objekt som tas upp av view funktionen.
Django anropar process_exception() när en vy ger upphov till ett undantag. process_exception() bör returnera antingen None eller ett HttpResponse-objekt. Om den returnerar ett HttpResponse-objekt kommer mallsvaret och svarsmellanvaran att tillämpas och det resulterande svaret returneras till webbläsaren. Annars börjar standardhantering av undantag gälla.
Återigen körs middleware i omvänd ordning under svarsfasen, som inkluderar process_exception. Om en undantagsmellanvara returnerar ett svar, kommer process_exception-metoderna i mellanvaruklasserna ovanför den mellanvaran inte att anropas alls.
process_template_response()¶
- process_template_response(request, response)¶
request är ett HttpRequest-objekt. response är TemplateResponse-objektet (eller motsvarande) som returneras av en Django-vy eller av en middleware.
process_template_response() anropas strax efter att vyn har körts färdigt, om svarsinstansen har en render()-metod, vilket indikerar att det är en TemplateResponse eller motsvarande.
Den måste returnera ett svarsobjekt som implementerar en render-metod. Det kan ändra det givna respons genom att ändra response.template_name och response.context_data, eller så kan det skapa och returnera en helt ny TemplateResponse eller motsvarande.
Du behöver inte uttryckligen rendera svaren - svaren renderas automatiskt när alla middleware för mallsvar har anropats.
Middleware körs i omvänd ordning under svarsfasen, som inkluderar process_template_response().
Hantering av strömmande svar¶
Till skillnad från HttpResponse har StreamingHttpResponse inte attributet content. Som ett resultat kan middleware inte längre anta att alla svar kommer att ha ett content-attribut. Om de behöver tillgång till innehållet måste de testa för strömmande svar och justera sitt beteende i enlighet därmed:
if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)
Observera
streaming_content bör antas vara för stort för att kunna hållas i minnet. Response middleware kan omsluta det i en ny generator, men får inte konsumera det. Omslag implementeras typiskt på följande sätt:
def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)
StreamingHttpResponse tillåter både synkrona och asynkrona iteratorer. Inkapslingsfunktionen måste matcha. Kontrollera StreamingHttpResponse.is_async om din mellanvara behöver stödja båda typerna av iteratorer.
Hantering av undantag¶
Django konverterar automatiskt undantag som tas upp av vyn eller av middleware till ett lämpligt HTTP-svar med en felstatuskod. Vissa undantag konverteras till 4xx-statuskoder, medan ett okänt undantag konverteras till en 500-statuskod.
Denna konvertering sker före och efter varje middleware (du kan tänka på det som den tunna filmen mellan varje lager av löken), så att varje middleware alltid kan lita på att få någon form av HTTP-svar tillbaka från anropet till dess get_response callable. Middleware behöver inte oroa sig för att linda in sitt anrop till get_response i en try/except och hantera ett undantag som kan ha uppstått av en senare middleware eller vyn. Även om nästa middleware i kedjan till exempel ger upphov till ett Http404-undantag, kommer din middleware inte att se det undantaget; istället får den ett HttpResponse-objekt med en status_code på 404.
Du kan sätta DEBUG_PROPAGATE_EXCEPTIONS till True för att hoppa över denna konvertering och sprida undantag uppåt.
Asynkront stöd¶
Middleware kan stödja alla kombinationer av synkrona och asynkrona förfrågningar. Django kommer att anpassa förfrågningar för att passa mellanvarans krav om det inte kan stödja båda, men med en prestandaförlust.
Som standard antar Django att din middleware endast kan hantera synkrona förfrågningar. För att ändra dessa antaganden, ställ in följande attribut på din middleware fabriksfunktion eller klass:
- sync_capableär en boolean som anger om mellanvaran kan hantera synkrona förfrågningar. Standardvärdet är- True.
- async_capableär en boolean som anger om mellanvaran kan hantera asynkrona förfrågningar. Standardvärdet är- False.
Om din middleware har både sync_capable = True och async_capable = True, kommer Django att skicka begäran utan att konvertera den. I det här fallet kan du räkna ut om din mellanvara kommer att ta emot asynkrona förfrågningar genom att kontrollera om get_response-objektet du skickas är en coroutine-funktion, med hjälp av asgiref.sync.iscoroutinefunction.
Modulen django.utils.decorators innehåller sync_only_middleware(), async_only_middleware(), och sync_and_async_middleware() decorators som låter dig tillämpa dessa flaggor på middleware-fabriksfunktioner.
Den returnerade callable måste matcha sync- eller async-karaktären hos get_response-metoden. Om du har en asynkron get_response måste du returnera en coroutine-funktion (async def).
metoderna process_view, process_template_response och process_exception, om de tillhandahålls, bör också anpassas för att matcha sync/async-läget. Django kommer dock att anpassa dem individuellt efter behov om du inte gör det, med en extra prestandaförlust.
Här är ett exempel på hur man skapar en middleware-funktion som stöder båda:
from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware
@sync_and_async_middleware
def simple_middleware(get_response):
    # One-time configuration and initialization goes here.
    if iscoroutinefunction(get_response):
        async def middleware(request):
            # Do something here!
            response = await get_response(request)
            return response
    else:
        def middleware(request):
            # Do something here!
            response = get_response(request)
            return response
    return middleware
Observera
Om du deklarerar en hybrid middleware som stöder både synkrona och asynkrona anrop, kanske den typ av anrop du får inte matchar den underliggande vyn. Django kommer att optimera anropsstacken för mellanvaran för att ha så få sync/async-övergångar som möjligt.
Även om du wrappar en asynkron vy kan du alltså bli anropad i synkront läge om det finns annan, synkron middleware mellan dig och vyn.
När du använder en asynkron klassbaserad middleware måste du se till att instanser är korrekt markerade som coroutine-funktioner:
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
class AsyncMiddleware:
    async_capable = True
    sync_capable = False
    def __init__(self, get_response):
        self.get_response = get_response
        if iscoroutinefunction(self.get_response):
            markcoroutinefunction(self)
    async def __call__(self, request):
        response = await self.get_response(request)
        # Some logic ...
        return response
Uppgradering av middleware i stil med före Django 1.10¶
- class django.utils.deprecation.MiddlewareMixin¶
Django tillhandahåller django.utils.deprecation.MiddlewareMixin för att underlätta skapandet av middleware-klasser som är kompatibla med både MIDDLEWARE och den gamla MIDDLEWARE_CLASSES, och som stöder synkrona och asynkrona förfrågningar. Alla middleware-klasser som ingår i Django är kompatibla med båda inställningarna.
Mixinen tillhandahåller en __init__()-metod som kräver ett get_response-argument och lagrar det i self.get_response.
Metoden __call__():
- Anropar - self.process_request(request)(om definierat).
- Anropar - self.get_response(request)för att hämta svaret från senare middleware och vyn.
- Anropar - self.process_response(request, response)(om definierat).
- Returnerar svaret. 
Om den används med MIDDLEWARE_CLASSES kommer metoden __call__() aldrig att användas; Django anropar process_request() och process_response() direkt.
I de flesta fall räcker det med att ärva från denna mixin för att göra en gammal middleware kompatibel med det nya systemet med tillräcklig bakåtkompatibilitet. Den nya semantiken för kortslutning kommer att vara harmlös eller till och med fördelaktig för den befintliga mellanprogramvaran. I några få fall kan en middleware-klass behöva ändras för att anpassas till den nya semantiken.
Detta är de beteendemässiga skillnaderna mellan att använda MIDDLEWARE och MIDDLEWARE_CLASSES:
- Under - MIDDLEWARE_CLASSESkommer varje middleware alltid att få sin metod- process_responseanropad, även om en tidigare middleware kortslöt genom att returnera ett svar från sin metod- process_request. Under- MIDDLEWAREbeter sig middleware mer som en lök: de lager som ett svar går igenom på vägen ut är samma lager som såg begäran på vägen in. Om en mellanvara kortsluts är det bara den mellanvaran och de före den i- MIDDLEWAREsom kommer att se svaret.
- Under - MIDDLEWARE_CLASSEStillämpas- process_exceptionpå undantag som uppstår från en- process_request-metod för mellanprogramvara. Under- MIDDLEWAREgäller- process_exceptionendast för undantag som uppstår från vyn (eller från- render-metoden i en- TemplateResponse). Undantag som tas upp från en mellanvara konverteras till lämpligt HTTP-svar och skickas sedan vidare till nästa mellanvara.
- Under - MIDDLEWARE_CLASSES, om en- process_response-metod ger upphov till ett undantag, hoppas- process_response-metoderna för alla tidigare mellanprogram över och ett- 500 Internal Server ErrorHTTP-svar returneras alltid (även om undantaget som gav upphov till t.ex. var en- Http404). Under- MIDDLEWARE, kommer ett undantag som uppstår från en middleware omedelbart att konverteras till lämpligt HTTP-svar, och sedan kommer nästa middleware i raden att se det svaret. Mellanprogram hoppas aldrig över på grund av att ett mellanprogram ger upphov till ett undantag.
 
          