فصل ۴: View، URL و Template

URLها: path و converterها، include، namespace و reverse

آدرس‌ها را اسم‌گذاری کنید، نه هاردکد

URLconf جنگو فهرستی از الگوهاست که از بالا به پایین بررسی می‌شوند و اولین تطابق برنده است. در پروژه‌ی تمیز، config/urls.py فقط مسیرهای اصلی را به اپ‌ها «include» می‌کند و هر اپ فایل urls خودش را دارد.

# config/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("manage-7f3a/", admin.site.urls),               # آدرس ادمین را حدس‌زدنی نگذارید
    path("orders/", include("apps.orders.urls")),
    path("api/", include("apps.api.urls")),
    path("", include("apps.pages.urls")),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

# apps/orders/urls.py
from django.urls import path, register_converter
from . import converters, views

register_converter(converters.TrackingCodeConverter, "tcode")

app_name = "orders"                                       # namespace
urlpatterns = [
    path("", views.OrderListView.as_view(), name="list"),
    path("new/", views.OrderCreateView.as_view(), name="create"),
    path("<int:pk>/", views.order_detail, name="detail"),
    path("<int:pk>/cancel/", views.cancel_order, name="cancel"),
    path("track/<tcode:code>/", views.track, name="track"),
]

converterها

converterتطبیقنوع در View
intارقام 0 تا 9int
strهر چیزی جز / (پیش‌فرض)str
slugحروف و ارقام لاتین، - و _str
uuidUUID با خط تیرهUUID
pathهر چیزی حتی /str

converter اختصاصی فقط یک کلاس با regex، to_python و to_url است:

# apps/orders/converters.py
class TrackingCodeConverter:
    regex = r"KSH[0-9A-F]{8}"

    def to_python(self, value):
        return value.upper()

    def to_url(self, value):
        return value

reverse: ساخت آدرس از روی نام

from django.urls import reverse, reverse_lazy

reverse("orders:detail", kwargs={"pk": 42})       # '/orders/42/'
reverse("orders:track", args=["KSH1A2B3C4D"])

class OrderCreateView(CreateView):
    success_url = reverse_lazy("orders:list")      # در سطح کلاس، lazy لازم است

در قالب: {% url 'orders:detail' pk=order.pk %}. اگر فردا آدرس را از orders/ به sefaresh/ تغییر دهید، هیچ لینکی نمی‌شکند.

نکته‌هایی که کمتر کسی می‌داند

  • اگر to_python یک converter استثنای ValueError بدهد، جنگو آن را «عدم تطابق» حساب می‌کند و سراغ الگوی بعدی می‌رود؛ راهی تمیز برای رد کردن مقادیر نامعتبر پیش از رسیدن به View.
  • با APPEND_SLASH (پیش‌فرض True) درخواست GET به /orders/42 به /orders/42/ ریدایرکت می‌شود؛ اما برای POST در DEBUG خطای RuntimeError می‌گیرید، چون داده‌ی POST در ریدایرکت از دست می‌رود.
  • در سطح کلاس و ماژول (success_url، تنظیمات LOGIN_URL) از reverse_lazy استفاده کنید؛ reverse در زمان import، قبل از بارگذاری URLconf، خطا می‌دهد.
  • python manage.py show_urls جزو جنگو نیست (از django-extensions است)؛ بدون آن هم می‌توانید در shell با get_resolver().reverse_dict الگوها را ببینید، یا resolve("/orders/42/") بزنید تا بفهمید آدرس به کدام View می‌رسد.
  • ثبت دوباره‌ی یک converter با همان نام در Django 5.1 به بعد منسوخ و خطاساز است؛ register_converter را فقط یک بار و در یک ماژول انجام دهید.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.