100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

URL Routing in Django

Learn how Django maps incoming request paths to views using urlpatterns, path converters, included URLconfs, and named URLs for reversible linking.

Views & URLsBeginner8 min readJul 10, 2026
Analogies

The URL Dispatcher and urlpatterns

Django routes every incoming request through a URLconf: a Python module (by convention urls.py) exposing a list called urlpatterns. Each entry, created with path() or re_path(), pairs a URL pattern with a view callable; Django's resolver walks urlpatterns top to bottom and dispatches the request to the first pattern that matches, so pattern order matters when patterns could overlap. The ROOT_URLCONF setting in settings.py tells Django which module to start resolving from for the whole project.

🏏

Cricket analogy: It's like an umpire's decision tree during an appeal: they check conditions in a fixed order — caught behind first, then LBW — and act on whichever rule matches first, just like Django checking patterns top to bottom.

Path Converters and Captured Parameters

path() uses angle-bracket syntax like <int:pk> or <slug:article_slug> to capture segments of the URL and convert them to Python types before passing them as keyword arguments to the view. Built-in converters include str (default), int, slug, uuid, and path (which greedily matches including slashes); you can also register custom converters by subclassing with a regex and to_python()/to_url() methods for domain-specific formats like ISO dates. re_path() remains available for cases needing full regular expressions that path()'s converters can't express.

🏏

Cricket analogy: It's like a scoring system that automatically converts a raw delivery outcome into a typed event — 'four runs' becomes an integer 4 in the scorecard, not just leftover text.

python
# project/urls.py
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
]

# blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'
urlpatterns = [
    path('', views.PostListView.as_view(), name='post_list'),
    path('<slug:post_slug>/', views.PostDetailView.as_view(), name='post_detail'),
    path('archive/<int:year>/<int:month>/', views.MonthArchiveView.as_view(), name='month_archive'),
]

Including URLconfs and Reversing Named URLs

include() lets a project's root urls.py delegate an entire URL prefix to an app's own urls.py, keeping each app's routing self-contained and enabling reuse across projects. Every path() should be given a name argument, and apps that might be included multiple times should set app_name to create a namespace; you then reference URLs in code with reverse('blog:post_detail', kwargs={'post_slug': 'my-post'}) or in templates with {% url 'blog:post_detail' post_slug=post.slug %}, so hardcoded URL strings never appear scattered through the codebase. This indirection means changing a URL pattern's path segment later requires editing only urls.py, not every template and view that links to it.

🏏

Cricket analogy: It's like a franchise structure where each state cricket association (app) runs its own domestic fixtures under the BCCI's (project's) overall umbrella, referenced by team name rather than hardcoded ground addresses.

Use reverse() (or the {% url %} template tag) everywhere instead of hardcoding paths like '/blog/my-post/' — this is what makes renaming a URL segment a one-line change in urls.py rather than a project-wide search-and-replace.

path() patterns are matched in order and the first match wins, so a broad pattern like path('<slug:page_slug>/', ...) placed above a more specific path('archive/', ...) will silently swallow requests intended for /archive/ — always order specific patterns before generic catch-alls.

  • Django resolves requests by walking urlpatterns top to bottom and dispatching to the first matching path().
  • ROOT_URLCONF in settings.py identifies the project's entry-point URLconf module.
  • Path converters (str, int, slug, uuid, path) capture and type-convert URL segments into view kwargs.
  • include() delegates a URL prefix to an app's own urls.py, keeping routing modular and reusable.
  • app_name creates a namespace so identically named URLs from different apps don't collide.
  • Always name your URL patterns and reference them via reverse() or {% url %} instead of hardcoding paths.
  • Pattern order matters: place specific patterns before broad/catch-all ones to avoid unintended matches.

Practice what you learned

Was this page helpful?

Topics covered

#Python#DjangoStudyNotes#WebDevelopment#URLRoutingInDjango#URL#Routing#Django#Dispatcher#StudyNotes#SkillVeris