درک ساختار ویوها و مدیریت خطا در جنگو

این مقاله به بررسی نحوه کار ویوهای جنگو، شیوه پردازش درخواست و تولید پاسخ، روش‌های بازگرداندن خطا با استفاده از HttpResponse و Http404، سفارشی‌سازی صفحات خطا، تست هندلرهای خطا و همچنین نوشتن ویوهای ناهمزمان در محیط ASGI می‌پردازد.

ویو جنگوHttpResponseHttp404

~4 دقیقه مطالعه • بروزرسانی ۲۳ اسفند ۱۴۰۴

مقدمه

یک view در جنگو تابعی پایتونی است که یک request دریافت کرده و یک response بازمی‌گرداند. این پاسخ می‌تواند یک صفحه HTML، یک redirect، یک تصویر، یک سند XML یا هر نوع محتوای دیگری باشد. جنگو هیچ محدودیتی برای محل قرارگیری کد ویو اعمال نمی‌کند؛ تنها شرط این است که در مسیر پایتون قابل دسترسی باشد. با این حال، به صورت قراردادی ویوها در فایلی به نام views.py داخل پوشه اپلیکیشن قرار می‌گیرند.


یک ویوی ساده

نمونه زیر یک ویو ساده را نشان می‌دهد که تاریخ و زمان فعلی را به صورت یک سند HTML بازمی‌گرداند:


from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = '<html lang="en"><body>It is now %s.</body></html>' % now
    return HttpResponse(html)

توضیح عملکرد ویو

  • کلاس HttpResponse از ماژول django.http و ماژول datetime پایتون ایمپورت می‌شود.
  • تابع current_datetime تعریف می‌شود. نام تابع اهمیتی ندارد و جنگو نام خاصی را الزام نمی‌کند.
  • هر ویو اولین آرگومان خود را به صورت یک شیء HttpRequest دریافت می‌کند.
  • تابع یک HttpResponse شامل محتوای HTML بازمی‌گرداند.

جنگو از تنظیم TIME_ZONE برای تعیین منطقه زمانی پیش‌فرض استفاده می‌کند. در صورت نیاز می‌توانید آن را در فایل تنظیمات تغییر دهید.


نگاشت URLها به ویوها

برای نمایش یک ویو در یک مسیر مشخص، باید آن را در URLconf تعریف کنید. این فایل الگوهای URL را به ویوها نگاشت می‌کند و جنگو هنگام دریافت درخواست، مسیر را با این الگوها تطبیق می‌دهد.


بازگرداندن خطاها

جنگو برای بسیاری از کدهای خطای HTTP کلاس‌های کمکی ارائه می‌دهد. برای مثال، HttpResponseNotFound یک پاسخ ۴۰۴ بازمی‌گرداند:


from django.http import HttpResponse, HttpResponseNotFound

def my_view(request):
    if foo:
        return HttpResponseNotFound("<h1>Page not found</h1>")
    else:
        return HttpResponse("<h1>Page was found</h1>")

همچنین می‌توانید کد وضعیت را مستقیماً مشخص کنید:


from django.http import HttpResponse

def my_view(request):
    return HttpResponse(status=201)

استفاده از استثنای Http404

به جای بازگرداندن دستی یک پاسخ ۴۰۴، می‌توانید استثنای Http404 را پرتاب کنید. جنگو این استثنا را گرفته و صفحه خطای استاندارد را نمایش می‌دهد.


from django.http import Http404
from django.shortcuts import render
from polls.models import Poll

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404("Poll does not exist")
    return render(request, "polls/detail.html", {"poll": p})

برای سفارشی‌سازی صفحه ۴۰۴، یک فایل 404.html در ریشه پوشه قالب‌ها ایجاد کنید. این فایل زمانی استفاده می‌شود که DEBUG برابر False باشد.


سفارشی‌سازی ویوهای خطا

می‌توانید ویوهای خطای پیش‌فرض جنگو را در URLconf اصلی پروژه بازنویسی کنید:


handler404 = "mysite.views.my_custom_page_not_found_view"
handler500 = "mysite.views.my_custom_error_view"
handler403 = "mysite.views.my_custom_permission_denied_view"
handler400 = "mysite.views.my_custom_bad_request_view"

برای سفارشی‌سازی خطای CSRF از تنظیم CSRF_FAILURE_VIEW استفاده کنید.


تست ویوهای خطای سفارشی

برای تست هندلرهای خطا، می‌توانید در یک ویو آزمایشی استثنا پرتاب کنید:


from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.test import SimpleTestCase, override_settings
from django.urls import path

def response_error_handler(request, exception=None):
    return HttpResponse("Error handler content", status=403)

def permission_denied_view(request):
    raise PermissionDenied

urlpatterns = [
    path("403/", permission_denied_view),
]

handler403 = response_error_handler

@override_settings(ROOT_URLCONF=__name__)
class CustomErrorHandlerTests(SimpleTestCase):
    def test_handler_renders_template_response(self):
        response = self.client.get("/403/")
        self.assertContains(response, "Error handler content", status_code=403)

ویوهای ناهمزمان

جنگو از ویوهای ناهمزمان با استفاده از async def پشتیبانی می‌کند. این ویوها در محیط ASGI اجرا شده و برای عملیات همزمان کارایی بالاتری دارند.


import datetime
from django.http import HttpResponse

async def current_datetime(request):
    now = datetime.datetime.now()
    html = '<html lang="en"><body>It is now %s.</body></html>' % now
    return HttpResponse(html)

برای اطلاعات بیشتر، به مستندات پشتیبانی ناهمزمان جنگو مراجعه کنید.


نوشته و پژوهش شده توسط دکتر شاهین صیامی