Pengolahan Tampilan Bersyarat

HTTP clients can send a number of headers to tell the server about copies of a resource that they have already seen. This is commonly used when retrieving a web page (using an HTTP GET request) to avoid sending all the data for something the client has already retrieved. However, the same headers can be used for all HTTP methods (POST, PUT, DELETE, etc.).

Untuk setiap halaman (tanggapan) yang Django kirim kembali dari tampilan, itu mungkin menyediakan dua kepala HTTP: kepala ETag dan Last-Modified. Kepala-kepala ini pilihan pada tanggapan HTTP. Mereka dapat disetel dengan fungsi tampilan anda, anda dapat bergantung pada middleware ConditionalGetMiddleware untuk menyetel kepala ETag.

Saat klien selanjutnya meminta sumber daya yang sama, klien mungkin mengirimkan kepala seperti If-Modified-Since atau If-Unmodified-Since, berisi tanggal waktu modifikasi terakhir dikirim, atau If-Match atau If-None-Match, berisi ETag terakhir yang dikirim. Jika versi halaman saat ini cocok dengan ETag yang dikirim oleh klien, atau jika sumber daya belum dirubah, kode status 304 dapat dikirim kembali, alih-alih tanggapan penuh, memberi tahu klien bahwa tidak ada yang berubah . Bergantung pada kepala, jika halaman telah dirubah atau tidak cocok dengan ETag yang dikirim oleh klien, kode status 412 (Prekondisi Gagal) dapat dikembalikan.

Ketika anda butuh lebih kendali lebih-halus anda mungkin menggunakan fungsi pengolahan bersyarat per-tampilan.

Penggias condition

Terkadang (sebenarnya, cukup sering) anda dapat membuat fungsi untuk menghitung nilai ETag dengan cepat atau waktu dirubah terakhir untuk sumber daya, tanpa perlu melakukan semua perhitungan yang diperlukan untuk membangun tampilan penuh. Django kemudian dapat menggunakan fungsi-fungsi ini untuk menyediakan pilihan "dana talangan awal" untuk pemrosesan tampilan. Memberitahu klien bahwa isi belum dimodifikasi sejak permintaan terakhir, mungkin.

Dua fungsi ini dilewatkan sebagai parameter pada penghias django.views.decorators.http.condition. Penghias ini menggunakan dua fungsi (anda hanya butuh menyokong satu, jika anda tidak dapat menghitung kedua jumlah dengan mudah dan cepat) untuk bekerja jika kepala dalam permintaan HTTP cocok dengan itu pada sumber daya. Jika mereka tidak cocok, sebuah salinan baru dari sumber daya harus dihitung dan tampilan biasa anda dipanggil.

Tanda tangan penghias condition terlihat seperti ini:

condition(etag_func=None, last_modified_func=None)

The two functions, to compute the ETag and the last modified time, will be passed the incoming request object and the same parameters, in the same order, as the view function they are helping to wrap. The function passed last_modified_func should return a standard datetime value specifying the last time the resource was modified, or None if the resource doesn't exist. The function passed to the etag decorator should return a string representing the ETag for the resource, or None if it doesn't exist.

Penghias menyetel kepala ETag dan Last-Modified pada tanggapan jika mereka tidak disetel oleh tampilan dan jika metode permintaan adalah aman (GET or HEAD).

Using this feature usefully is probably best explained with an example. Suppose you have this pair of models, representing a small blog system:

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

Jika halaman depan, menampilkan masukan blog terakhir, hanya perubahan ketika anda menambah masukan blog baru, anda dapat menghitung waktu terakhir dirubah sangat cepat. Anda butuh tanggal published terakhir untuk setiap masukan terkait dengan blog itu. Satu cara melakukan ini adalah:

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

Anda lalu dapat menggunakan fungsi ini untuk menyediakan pengenalan awal dari halaman tidak berubah untuk tampilan halaman depan anda:

from django.views.decorators.http import condition


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

Hati-hati dengan urutan dari penghias

Saat condition() mengembalikan tanggapan bersyarat, setiap dekorator di bawahnya akan dilewati dan tidak akan diterapkan ke tanggapan. Oleh karena itu, setiap dekorator yang perlu diterapkan pada tanggapan tampilan reguler dan tanggapan bersyarat harus berada di atas condition(). Khususnya, vary_on_cookie(), vary_on_headers(), dan ~django.views.decorators.cache.cache_control ` harus didahulukan karena :rfc:`RFC 9110 mengharuskan kepala yang mereka atur ada pada tanggapan 304.

Jalan pintas untuk hanya menghitung satu nilai

Sebagai aturan umum, jika anda dapat menyediakan fngsi untuk menghitung kedua ETag dan waktu perubahan terakhir, anda harus melakukannya. Anda tidak mengetahui kepala klien HTTP diberikan akan mengirim anda, jadi bersiap-siap untuk menangani keduanya, terkadang hanya satu nilai adalah mudah untuk dihitung dan Django menyediakan penghias yang menangani hanya ETag atau hanya perhitungan dirubah-terakhir.

Penghias django.views.decorators.http.etag dan django.views.decorators.http.last_modified dilewatkan jenis sama dari fungsi seperti penghias condition. Tanda tangan mereka adalah:

etag(etag_func)
last_modified(last_modified_func)

Kami dapat menulis contoh paling awal, yang hanya menggunakan fungsi dirubah-terakhir, menggunakan satu dari penghias ini:

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

...atau:

def front_page(request, blog_id):
    ...


front_page = last_modified(latest_entry)(front_page)

Gunakan kondisi ketika menguji kedua kondisi

Itu mungkin terlihat lebih baik bagi beberapa orang mencoba dan mengikat penghias etag dan last_modified jika anda ingin mencoba kedua prakeadaan. bagaimanapun, ini akan membawa perilaku tidak benar.

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


# End of bad code.

Penghias pertama tidak mengetahui apapun tentang kedua dan mungkin menjawab tanggapan itu tidak dirubah meskipun jika penghias kedua akan menentukan sebaliknya. Penghias condition menggunakan kedua fugnsi callback secara terus menerus untuk bekerja tindakan tepat diambil.

Menggunakan penghias dengan metode HTTP lain

Penghias condition berguna untuk lebih dari hanya permintaan GET dan HEAD (permintaan HEAD adalah sama seperti GET dalam keadaan ini). Itu dapat juga digunakan untuk menyediakan pemeriksaan untuk perintaan POST, PUT dan DELETE. Dalam keadaan ini, ide bukan mengembalikan sebuah tanggapan "not modified", tetapi memberitahu klien yang sumber daya mereka sedang mencoba telah dirubah dalam sementara itu.

Sebagai contoh, pertimbangkan pertukaran berikut diantara klien dan peladen:

  1. Permintaan klien /foo/.
  2. Tanggapan peladen dengan beberapa isi dengan sebuah ETag dari "abcd1234".
  3. Klien mengirim sebuah permintaan PUT HTTP pada /foo/ untuk memperbaharui sumber daya. Itu juga mengirim sebuah kepala If-Match: "abcd1234" untuk menentukan versi itu coba memperbaharui.
  4. Peladen memeriksa untuk melihat jika sumber daya telah berubah, dengan menghitung ETag cara sama itu lakukan untuk permintaan GET (menggunakan fungsi sama). Jika sumber data telah berubah, itu akan mengembalikan kode keadaan 412, berarti "Prasyarat gagal".
  5. Klien mengirim sebuah permintaan GET pada /foo/, setelah menerima tanggapan 412, untuk mengambil sebuah versi terperbaharui dari isi sebelum memperbaharui itu.

Hal terpenting contoh ini menunjukkan bahwa fungsi sama dapat digunakan untuk menghitung ETAg dan nilai perubahan terakhir dalam semua keadaan. Faktanya, anda harus menggunakan fungsi sama, sehingga nilai sama dikembalikan setiap waktu.

Kepala-kepala pengesah dengan metode permintaan tidak-aman

Dekorator condition hanya menetapkan pengesah kepala (ETag dan Last-Modified) untuk metode HTTP yang aman, yaitu GET dan HEAD. Jika anda ingin mengembalikannya dalam kasus lain, atur dalam tampilan anda. Lihat RFC 9110#section-9.3.4 untuk mempelajari tentang perbedaan antara menyetel pengesah kepala sebagai tanggapan terhadap permintaan yang dibuat dengan PUT melawan POST.

Perbandingan dengan pengolahan bersyarat middleware

Django provides conditional GET handling via django.middleware.http.ConditionalGetMiddleware. While being suitable for many situations, the middleware has limitations for advanced usage:

  • Itu diberlakukan secara global pada semua tampilan dalam proyek anda.
  • Itu tidak menyimpan anda dari membangkitkan tanggapan, yang mungkin mahal.
  • Itu hanya sesuai untuk permintaan GET HTTP.

Anda harus memilih alat paling sesuai untuk masalah tertentu anda disini. Jika anda mempunyai cara menghitung ETags dan waktu perubahan sangat cepat dan jika beberapa tampilan perlu waktu untuk membangkitkan isi, anda harus mempertimbangkan menggunakan penghias decorator digambarkan dalam dokumen ini. Jika semuanya sudah berjalan cukup cepat, lekatkan menggunakan middleware dan sejumlah lalu lintas jaringan dikirim kembali ke klien akan masih dikurangi jika tampilan belum berubah.

Back to Top