URL configuration (URLconf) defines the structure of a Django website, mapping URL patterns to corresponding view functions.
URLconf Structure
The basic format is as follows:
from django.conf.urls import url
urlpatterns = [
url(regex_pattern, view_function, name, kwargs)
]
- regex_pattern: A regular expression to match the incoming URL path.
- view_function: A callable view function or class-based view.
- name: An optional identifier for reverse URL lookups.
- kwargs: An optional dictionary of additional arguments to pass to the view.
- urlpatterns: A list containing
url()objects.
Pattern Syntax Across Versions
Django 1.11 syntax:
from django.conf.urls import url
from myapp import views
urlpatterns = [
url(r'^user/(\d+)/$', views.user_detail),
]
Django 2.0+ syntax:
from django.urls import path, re_path
from myapp import views
urlpatterns = [
path('user/<int:user_id>/', views.user_detail),
re_path(r'^user/(\d+)/$', views.user_detail),
]
Important Notes:
- Patterns in
urlpatternsare evaluated sequentially; the first match terminates the search. - Parentheses
()in regex create capturing groups for paarmeter extraction. - Leading slashes are not required in patterns.
- The
rprefix before regex strings is optional but recommendde for raw strings. - The
APPEND_SLASHsetting (defaultTrue) automatically redirects requests missing a trailing slash.
Parameter Capture in URL Patterns
Captured values from the URL are passed to the view function.
Positional Arguments
Simple parentheses create unnamed groups, passing values as positional arguments.
# urls.py
from django.conf.urls import url
from catalog import views
urlpatterns = [
url(r'^archive/(\d{4})/(\d{2})/$', views.monthly_archive),
]
# views.py
from django.http import HttpResponse
def monthly_archive(request, year, month):
return HttpResponse(f'Archive for {year}/{month}')
Keyword Arguments
Named groups using (?P<name>pattern) pass values as keyword arguments.
# urls.py
from django.conf.urls import url
from catalog import views
urlpatterns = [
url(r'^book/(?P<book_id>\d+)/$', views.book_detail),
]
# views.py
from django.http import HttpResponse
def book_detail(request, book_id):
return HttpResponse(f'Book ID: {book_id}')
The parameter name in the pattern must match the view function's argument name.
URLconf Matching Behavior
URLconf matches only the path component of a URL, ignoring the domain, query string (?key=value), and request method (GET, POST, etc.).
# urls.py
from django.conf.urls import url
from myapp import views
urlpatterns = [
url(r'^$', views.index),
]
# views.py
from django.http import HttpResponse
from django.shortcuts import render
def index(request):
# Access query parameters or form data manually
user = request.GET.get('user') or request.POST.get('user')
if user:
return HttpResponse(f'User: {user}')
return render(request, 'form.html')
Additional URL Configuration Features
Default Parameter Values in Views
Views can define default values for URL parameters.
# urls.py
from django.conf.urls import url
from myapp import views
urlpatterns = [
url(r'^page/$', views.paginated_view),
url(r'^page(?P<page_num>\d+)/$', views.paginated_view),
]
# views.py
from django.http import HttpResponse
def paginated_view(request, page_num='1'):
return HttpResponse(f'Page {page_num}')
Passing Extra Options to Views
A dictionary of extra keyword arguments can be passed via the url() function.
from django.conf.urls import url
from myapp import views
urlpatterns = [
url(r'^report/(?P<year>\d{4})/$', views.annual_report, {'format': 'pdf'}),
]
# Calls views.annual_report(request, year='2023', format='pdf')
If a named group and an extra dictionary key conflict, the dictionary value takes precedence.
Passing Extra Options to include()
Extra options can be forwarded to all URL patterns within an included module.
# project/urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^blog/', include('blog.urls'), {'category': 'tech'}),
]
# blog/urls.py
from django.conf.urls import url
from blog import views
urlpatterns = [
url(r'^posts/$', views.post_list), # Receives category='tech'
url(r'^about/$', views.about), # Receives category='tech'
]
Ensure all views in the included module accept the extra parameters.
Modular URL Design with include()
Use include() to delegate URL patterns to app-specific modules, reducing redundancy.
# project/urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^store/', include('store.urls')),
]
# store/urls.py
from django.conf.urls import url
from store import views
urlpatterns = [
url(r'^$', views.storefront),
url(r'^product/(\d+)/$', views.product_detail),
url(r'^cart/$', views.view_cart),
]
When Django encounters include(), it strips the matched portion of the URL and passes the remainder to the included URLconf.
Reverse URL Resolution
Reverse resolution generates URLs from view names and arguments, avoiding hardcoded URLs.
- In templates: Use the
{% url %}tag. - In Python code: Use the
reverse()function. - In models: Define a
get_absolute_url()method.
# urls.py
from django.conf.urls import url
from orders import views
urlpatterns = [
url(r'^order/(?P<order_id>\d+)/$', views.order_details, name='order_detail'),
]
# In a view
from django.urls import reverse
from django.http import HttpResponseRedirect
def process_order(request):
# ...
url = reverse('order_detail', kwargs={'order_id': 123})
return HttpResponseRedirect(url)
URL Namespaces
Namespaces prevent naming conflicts when using include() with multiple apps.
# project/urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', include('admin.urls', namespace='admin')),
url(r'^api/', include('api.urls', namespace='api')),
]
# Reverse with namespace
reverse('admin:login')
reverse('api:user_list')