Khi request đến, Django duyệt request.path với danh sách urlpatterns theo thứ tự khai báo, dùng path() hoặc re_path().
Match xong thì capture group được pass vào view tương ứng.
python
# config/urls.py (root)
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('apps.api.urls')),
path('blog/', include('apps.blog.urls', namespace='blog')),
]
# apps/blog/urls.py
app_name = 'blog'
urlpatterns = [
path('', views.PostListView.as_view(), name='post-list'),
path('<slug:slug>/', views.PostDetailView.as_view(), name='post-detail'),
]Mỗi app giữ urls.py riêng và khai app_name namespace, sau đó reverse URL qua reverse('blog:post-detail', kwargs={...}) thay vì hard-code path. Khi đổi URL, chỉ cần sửa một chỗ.
Vì match theo thứ tự, path('<slug:slug>/') phải đặt sau các path tĩnh như path('new/', ...). Đảo lại là slug sẽ nuốt mất /new/, view tĩnh không bao giờ được gọi.