# Django 6.0.7 documentation

# Behandling av villkorlig vy

HTTP-klienter kan skicka ett antal rubriker för att berätta för servern om kopior av en resurs som de redan har sett. Detta används ofta när man hämtar en webbsida (med en HTTP `GET`-begäran) för att undvika att skicka alla data för något som klienten redan har hämtat. Samma rubriker kan dock användas för alla HTTP-metoder (`POST`, `PUT`, `DELETE`, etc.).

För varje sida (svar) som Django skickar tillbaka från en vy kan den tillhandahålla två HTTP-rubriker: rubriken `ETag` och rubriken `Last-Modified`. Dessa rubriker är valfria på HTTP-svar. De kan ställas in av din vyfunktion, eller så kan du förlita dig på `ConditionalGetMiddleware` middleware för att ställa in `ETag`-rubriken.

When the client next requests the same resource, it might send along a header such as either If-Modified-Since or If-Unmodified-Since, containing the date of the last modification time it was sent, or either If-Match or If-None-Match, containing the last `ETag` it was sent. If the current version of the page matches the `ETag` sent by the client, or if the resource has not been modified, a 304 status code can be sent back, instead of a full response, telling the client that nothing has changed. Depending on the header, if the page has been modified or does not match the `ETag` sent by the client, a 412 status code (Precondition Failed) may be returned.

När du behöver mer finkornig kontroll kan du använda funktioner för villkorlig bearbetning per vy.

## Dekoratorn `condition` (villkor)

Ibland (faktiskt ganska ofta) kan du skapa funktioner för att snabbt beräkna ETag-värdet eller den senast modifierade tiden för en resurs, utan att behöva göra alla beräkningar som krävs för att konstruera hela vyn. Django kan sedan använda dessa funktioner för att tillhandahålla ett ”tidigt bailout”-alternativ för vybehandlingen. Att tala om för klienten att innehållet inte har ändrats sedan den senaste begäran, kanske.

Dessa två funktioner skickas som parametrar till dekoratorn `django.views.decorators.http.condition`. Denna dekorator använder de två funktionerna (du behöver bara tillhandahålla en, om du inte kan beräkna båda kvantiteterna enkelt och snabbt) för att räkna ut om rubrikerna i HTTP-begäran matchar dem på resursen. Om de inte matchar måste en ny kopia av resursen beräknas och din normala vy anropas.

Signaturen för dekoratorn `condition` ser ut så här:

    condition(etag_func=None, last_modified_func=None)

De två funktionerna, för att beräkna ETag och den senaste modifieringstiden, kommer att skickas till det inkommande `request`-objektet och samma parametrar, i samma ordning, som den vyfunktion de hjälper till att omsluta. Funktionen som skickas `last_modified_func` bör returnera ett standard datetime-värde som anger den senaste gången resursen ändrades, eller `None` om resursen inte finns. Funktionen som skickas till `etag`-dekoratorn bör returnera en sträng som representerar ETag för resursen, eller `None` om den inte existerar.

Dekoratorn ställer in rubrikerna `ETag` och `Last-Modified` på svaret om de inte redan är inställda av vyn och om begärans metod är säker (`GET` eller `HEAD`).

Att använda den här funktionen på ett användbart sätt förklaras förmodligen bäst med ett exempel. Anta att du har det här paret av modeller, som representerar ett litet bloggsystem:

    import datetime
    from django.db import models

    class Blog(models.Model): ...

    class Entry(models.Model):
        blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
        published = models.DateTimeField(default=datetime.datetime.now)
        ...

Om förstasidan, som visar de senaste blogginläggen, bara ändras när du lägger till ett nytt blogginlägg, kan du beräkna den senaste ändringstiden mycket snabbt. Du behöver det senaste `publicerade` datumet för varje post som är associerad med den bloggen. Ett sätt att göra detta skulle vara:

    def latest_entry(request, blog_id):
        return Entry.objects.filter(blog=blog_id).latest("published").published

Du kan sedan använda den här funktionen för att tidigt upptäcka en oförändrad sida för din förstasidesvisning:

    from django.views.decorators.http import condition

    @condition(last_modified_func=latest_entry)
    def front_page(request, blog_id): ...

Var försiktig med beställningen av dekoratörer

När `condition()` returnerar ett villkorligt svar, kommer alla dekoratorer under det att hoppas över och inte gälla för svaret. Därför måste alla dekoratorer som behöver tillämpas på både det vanliga vy-svaret och ett villkorligt svar vara ovanför `condition()`. I synnerhet bör `vary_on_cookie()`, `vary_on_headers()` och `cache_control()` komma först eftersom RFC 9110 kräver att de rubriker som de anger ska finnas på 304-svar.

## Kortkommandon för att bara beräkna ett värde

Som en allmän regel gäller att om du kan tillhandahålla funktioner för att beräkna både ETag och senast ändrade tid, bör du göra det. Du vet inte vilka headers en given HTTP-klient kommer att skicka till dig, så var beredd att hantera båda. Ibland är det dock bara ett värde som är lätt att beräkna och Django tillhandahåller dekoratorer som endast hanterar ETag eller endast senast modifierade beräkningar.

Dekoratorerna `django.views.decorators.http.etag` och `django.views.decorators.http.last_modified` passerar samma typ av funktioner som dekoratorn `condition`. Deras signaturer är:

    etag(etag_func)
    last_modified(last_modified_func)

Vi kan skriva det tidigare exemplet, som bara använder en senast modifierad funktion, med hjälp av en av dessa dekoratorer:

    @last_modified(latest_entry)
    def front_page(request, blog_id): ...

…eller:

    def front_page(request, blog_id): ...

    front_page = last_modified(latest_entry)(front_page)

### Använd `condition` när du testar båda villkoren

Det kan se trevligare ut för vissa människor att försöka kedja dekoratorerna `etag` och `last_modified` om du vill testa båda förutsättningarna. Detta skulle dock leda till felaktigt beteende.

    # Bad code. Don't do this!
    @etag(etag_func)
    @last_modified(last_modified_func)
    def my_view(request): ...

    # End of bad code.

Den första dekoratorn vet ingenting om den andra och kan svara att svaret inte ändras även om den andra dekoratorn skulle bestämma något annat. Dekoratorn `condition` använder båda callback-funktionerna samtidigt för att räkna ut vilken åtgärd som ska vidtas.

## Använda dekoratorerna med andra HTTP-metoder

Dekoratorn `condition` är användbar för mer än bara `GET` och `HEAD` förfrågningar (`HEAD` förfrågningar är samma sak som `GET` i denna situation). Den kan också användas för att kontrollera `POST`, `PUT` och `DELETE` förfrågningar. I dessa situationer är tanken inte att returnera ett ”not modified”-svar, utan att tala om för klienten att den resurs som de försöker ändra har ändrats under tiden.

Tänk till exempel på följande utväxling mellan klienten och servern:

1. Klienten begär `/foo/`.

2. Servern svarar med en del innehåll med ETag `"abcd1234"`.

3. Klienten skickar en HTTP `PUT`-förfrågan till `/foo/` för att uppdatera resursen. Den skickar också en `If-Match: "abcd1234"` header för att ange den version som den försöker uppdatera.

4. Servern kontrollerar om resursen har ändrats genom att beräkna ETag på samma sätt som för en `GET`-begäran (med samma funktion). Om resursen har ändrats returneras en statuskod på 412, vilket betyder att ”förvillkoret misslyckades”.

5. Klienten skickar en `GET`-förfrågan till `/foo/`, efter att ha fått ett 412-svar, för att hämta en uppdaterad version av innehållet innan det uppdateras.

Det viktiga som exemplet visar är att samma funktioner kan användas för att beräkna ETag-värdet och värdet för senaste ändring i alla situationer. Faktum är att du bör använda samma funktioner, så att samma värden returneras varje gång.

Valideringshuvuden med osäkra förfrågningsmetoder

Dekoratorn `condition` ställer endast in valideringsrubriker (`ETag` och `Last-Modified`) för säkra HTTP-metoder, dvs `GET` och `HEAD`. Om du vill returnera dem i andra fall, ställ in dem i din vy. Se RFC 9110 Section 9.3.4 för att lära dig mer om skillnaden mellan att ställa in en validator header som svar på förfrågningar gjorda med `PUT` kontra `POST`.

## Jämförelse med middleware villkorlig bearbetning

Django tillhandahåller villkorlig `GET`-hantering via `django.middleware.http.ConditionalGetMiddleware`. Även om det är lämpligt för många situationer har mellanvaran begränsningar för avancerad användning:

- Den tillämpas globalt på alla vyer i ditt projekt.

- Det innebär inte att du slipper generera svaret, vilket kan bli dyrt.

- Det är endast lämpligt för HTTP `GET`-förfrågningar.

Här bör du välja det lämpligaste verktyget för just ditt problem. Om du har ett sätt att snabbt beräkna ETags och ändringstider och om det tar en stund för en vy att generera innehållet bör du överväga att använda dekoratorn `condition` som beskrivs i det här dokumentet. Om allt redan går ganska snabbt kan du hålla dig till att använda mellanvaran och mängden nätverkstrafik som skickas tillbaka till klienterna kommer fortfarande att minskas om vyn inte har ändrats.