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.
# 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
1. What determines which view handles an incoming request when multiple URL patterns could match?
2. Which path converter would you use to capture an integer primary key from a URL?
3. What is the purpose of app_name in an app's urls.py?
4. Why should templates use {% url 'name' %} instead of hardcoded paths?
Was this page helpful?
You May Also Like
Function-Based Views
Learn how Django's function-based views (FBVs) take a request and return a response using plain Python functions, and when they're the right choice over class-based views.
Class-Based Views
Understand how Django's class-based views (CBVs) organize request handling into methods on a class, and how generic CBVs and mixins reduce boilerplate for common patterns like CRUD.
Django Templates
Learn Django's built-in template language — variables, tags, filters, template inheritance, and how the template engine renders context into HTML safely.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentNext.js Study Notes
JavaScript · 30 topics