پردازش شرطی ویوها در جنگو: ETag، Last-Modified و دکوراتور condition

این مقاله نحوهٔ پردازش شرطی درخواست‌های HTTP در جنگو را توضیح می‌دهد. موضوعاتی مانند هدرهای ETag و Last-Modified، دکوراتور condition، دکوراتورهای etag و last_modified، استفاده از پردازش شرطی در متدهای غیرایمن (POST/PUT/DELETE) و مقایسهٔ آن با ConditionalGetMiddleware بررسی می‌شوند.

پردازش شرطی جنگو، ETag، Last-Modifiedcondition decorator، If-Modified-Since، If-None-Match304 Not Modified، 412 Precondition Failed

~3 min read • Updated Mar 15, 2026

مقدمه

کلاینت‌های HTTP می‌توانند هدرهایی ارسال کنند که نشان می‌دهد نسخهٔ قبلی یک منبع را قبلاً دریافت کرده‌اند. این کار باعث می‌شود سرور در صورت عدم تغییر محتوا، پاسخ کامل ارسال نکند. جنگو از طریق هدرهای ETag و Last-Modified از این قابلیت پشتیبانی می‌کند.

اگر کلاینت هدرهایی مانند If-Modified-Since یا If-None-Match ارسال کند، جنگو می‌تواند به‌جای پاسخ کامل، وضعیت 304 Not Modified برگرداند. اگر نسخهٔ منبع تغییر کرده باشد، ممکن است وضعیت 412 Precondition Failed بازگردانده شود.


دکوراتور condition

برای کنترل دقیق‌تر، جنگو دکوراتور condition() را ارائه می‌دهد. این دکوراتور دو تابع اختیاری دریافت می‌کند:

  • etag_func: تولیدکنندهٔ مقدار ETag
  • last_modified_func: تولیدکنندهٔ زمان آخرین تغییر

این توابع همان آرگومان‌های ویو را دریافت می‌کنند و به جنگو اجازه می‌دهند قبل از اجرای کامل ویو، بررسی کنند که آیا محتوا تغییر کرده است یا نه.

امضا


condition(etag_func=None, last_modified_func=None)

مثال

فرض کنید صفحهٔ اصلی یک وبلاگ فقط زمانی تغییر می‌کند که یک پست جدید منتشر شود:


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

می‌توان از این تابع برای پردازش شرطی استفاده کرد:


from django.views.decorators.http import condition

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

هشدار دربارهٔ ترتیب دکوراتورها

دکوراتورهایی مانند vary_on_cookie()، vary_on_headers() و cache_control() باید قبل از condition() قرار بگیرند. زیرا اگر condition پاسخ 304 بدهد، دکوراتورهای زیر آن اجرا نمی‌شوند.


میان‌بُرها: etag() و last_modified()

اگر فقط یکی از مقادیر ETag یا Last-Modified را نیاز دارید، می‌توانید از دکوراتورهای ساده‌تر استفاده کنید:


etag(etag_func)
last_modified(last_modified_func)

مثال


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

از chain کردن etag و last_modified خودداری کنید

این کار اشتباه است:


@etag(etag_func)
@last_modified(last_modified_func)
def my_view(request):
    ...

هر دکوراتور مستقل عمل می‌کند و ممکن است نتیجهٔ اشتباه بدهد. برای استفاده از هر دو مقدار، فقط از condition() استفاده کنید.


استفاده در متدهای غیرایمن (POST/PUT/DELETE)

پردازش شرطی فقط برای GET و HEAD نیست. در متدهای PUT، POST و DELETE نیز می‌تواند از تغییرات ناخواسته جلوگیری کند.

مثال

  1. کلاینت GET می‌زند و ETag = "abcd1234" دریافت می‌کند.
  2. کلاینت PUT می‌زند و هدر If-Match: "abcd1234" ارسال می‌کند.
  3. سرور ETag جدید را محاسبه می‌کند.
  4. اگر تغییر کرده باشد → 412 Precondition Failed.
  5. کلاینت GET جدید می‌زند تا نسخهٔ تازه را دریافت کند.

این روش از overwrite شدن داده‌های تغییر کرده جلوگیری می‌کند.

هدرهای اعتبارسنجی در متدهای غیرایمن

دکوراتور condition() فقط برای GET و HEAD هدرهای ETag و Last-Modified را تنظیم می‌کند. اگر می‌خواهید در PUT یا POST هم ارسال شوند، باید در ویو تنظیم کنید.


مقایسه با ConditionalGetMiddleware

جنگو middleware مخصوص GET شرطی دارد: ConditionalGetMiddleware. اما محدودیت‌هایی دارد:

  • برای همهٔ ویوها اعمال می‌شود
  • از اجرای ویو جلوگیری نمی‌کند (حتی اگر گران باشد)
  • فقط برای GET مناسب است

از condition() استفاده کنید اگر:

  • می‌توانید ETag یا Last-Modified را سریع محاسبه کنید
  • ویو سنگین است
  • نیاز به پردازش شرطی برای PUT/POST/DELETE دارید

از middleware استفاده کنید اگر:

  • ویوها سریع هستند
  • فقط GET شرطی نیاز دارید

جمع‌بندی

پردازش شرطی ویوها در جنگو ابزار قدرتمندی برای بهینه‌سازی عملکرد و جلوگیری از تغییرات ناخواسته است. با استفاده از ETag، Last-Modified، دکوراتور condition و هدرهای شرطی HTTP، می‌توانید از ارسال داده‌های غیرضروری جلوگیری کنید و هم‌زمان یک سیستم امن و سازگار با استانداردهای HTTP بسازید.

Written & researched by Dr. Shahin Siami