CodeOath
← All posts
Python70 min total · 18 parts

Django Fundamentals: MVT Architecture, the ORM, and Middleware

Contents — Part 10 of 18: URLs and URL Routing
Part 10 of 18 · ~1 min

URLs and URL Routing

# myproject/urls.py — the project's root URL configuration
urlpatterns = [
    path("admin/", admin.site.urls),
    path("orders/", include("orders.urls")),   # delegate everything under /orders/ to the app
]

# orders/urls.py — the app's own URL configuration
urlpatterns = [
    path("", views.order_list, name="order-list"),
    path("<int:pk>/", views.order_detail, name="order-detail"),
    path("<int:pk>/edit/", views.order_edit, name="order-edit"),
]

include() is what lets an app own its own URL namespace, keeping the root urls.py a short table of contents rather than one giant flat list. Path converters (<int:pk>, <slug:slug>, <str:name>) both extract the value from the URL and validate/convert its type — <int:pk> on /orders/abc/ doesn't match at all (falls through to a 404) rather than passing the string "abc" through to the view.

Named URLs and reverse() — never hardcode a URL string

# In a template
<a href="{% url 'order-detail' order.pk %}">View order</a>

# In Python code
from django.urls import reverse
url = reverse("order-detail", args=[order.pk])

Referencing a URL by its name (set in path(..., name="order-detail")) rather than hardcoding the string /orders/5/ means the actual URL structure can change in one place (urls.py) without breaking every template and redirect that links to it — this indirection is the entire point of naming URL patterns, and hardcoded URL strings scattered through templates are a common code-review flag.