Django URL Routing
The routing layer (URLconf) is Django’s configuration for mapping URLs to view functions. This article covers how to define routes, regex matching rules, named and unnamed groups, reverse URL resolution, route distribution (include), and the path / re_path syntax introduced in Django 2.x.
Routing Layer
What is Routing?
A route is the mapping relationship between a request URL and a view function.Route Configuration
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(regex, view_function, kwargs, name),
]
# regex — a regular expression string
# view — a callable (usually a view function) or a dotted path string to one
# kwargs — optional default arguments passed to the view (as a dict)
# name — an optional alias for the route
# Regex rules:
# 1. Patterns are matched top-to-bottom; the first match wins and no further
# patterns are tried.
# 2. To capture a value from the URL, wrap the relevant part in parentheses (grouping).
# 3. Do not add a leading slash; every URL already has one. Use ^articles, not ^/articles.
# 4. The 'r' prefix on each pattern string is optional but recommended.
#
# In settings.py, APPEND_SLASH controls whether Django appends a trailing slash:
# APPEND_SLASH = True (default — enabled)
urlpatterns = [
url(r'^admin/', admin.site.urls),
# Homepage
url(r'^$', views.home),
# Route matching
url(r'^test/$', views.test),
url(r'^testadd/$', views.testadd),
# Catch-all / error page (for reference)
url(r'', views.error),
]Grouping
# What is grouping?
# Simply put, grouping means wrapping part of a regex in parentheses.
# There are two kinds: unnamed groups and named groups.
# Unnamed groups:
# An unnamed group passes the matched content to the view as a positional argument.
urlpatterns = [
url(r'^admin/', admin.site.urls),
# The regex below matches paths like: article/<number>/
# The matched group value is passed as a positional argument to the view.
# Number of positional args equals the number of groups.
url(r'^aritcle/(\d+)/$', views.article),
]
# views.py must accept an extra parameter to receive the captured group value
def article(request, article_id):
return HttpResponse('Article with id %s ...' % article_id)
# Named groups:
# A named group passes the matched content to the view as a keyword argument.
urlpatterns = [
url(r'^admin/', admin.site.urls),
# The regex below matches paths like: article/<number>/
# The matched group is passed as a keyword argument: article_id=<matched number>
url(r'^aritcle/(?P<article_id>\d+)/$', views.article),
]
# The parameter name in views.py must match the name defined in urls.py
def article(request, article_id):
return HttpResponse('Article with id %s ...' % article_id)
# Difference between named and unnamed groups:
# Both capture URL parameters and pass them to the view function.
# Unnamed groups use positional arguments; named groups use keyword arguments.
# Named and unnamed groups cannot be mixed, but each type can appear multiple times.Reverse URL Resolution
# What is reverse URL resolution?
# Using certain methods to obtain a result that can be used directly to access
# the corresponding URL and trigger the view function.
# Configuration:
# First, give the route an alias (name)
url(r'^func_kkk/', views.func, name='ooo')
# Backend reverse resolution
from django.shortcuts import render, HttpResponse, redirect, reverse
reverse('ooo')
# Frontend reverse resolution (in templates)
<a href="{% url 'ooo' %}">link text</a>
# Note: aliases must be unique
# Reverse resolution with named and unnamed groups:
# Unnamed group reverse resolution:
url(r'^index/(\d+)/', views.index, name='xxx')
# Frontend:
{% url 'xxx' 123 %}
# Backend:
reverse('xxx', args=(1,))
# Named group reverse resolution:
url(r'^func/(?P<year>\d+)/', views.func, name='ooo')
# Frontend:
<a href="{% url 'ooo' year=123 %}">method 1</a>
<a href="{% url 'ooo' 123 %}">method 2</a>
# Backend:
reverse('ooo', kwargs={'year': 123}) # method 1
reverse('ooo', args=(111,)) # method 2
# When using reverse resolution in the backend, import the module first:
from django.shortcuts import reverseRoute Distribution
# Each Django app can have its own templates folder, urls.py, and static folder.
# In a company, a project may have many modules, each maintained by different people.
# When a Django project has many URLs, the main urls.py becomes very long and hard
# to maintain. Route distribution lets us split URL definitions into per-app files.
# With route distribution, the main urls.py no longer maps URLs directly to view
# functions. Instead it identifies which app a URL belongs to and delegates it there.
# Once a prefix matches, processing stops and the matched app handles the rest.
# Main urls.py (two equivalent approaches):
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls),
# Approach 1: import and reference
url(r'^app01/', include(app01_urls)), # All URLs starting with app01 go to app01
url(r'^app02/', include(app02_urls)), # All URLs starting with app02 go to app02
# Approach 2: use string path (recommended)
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
# Important: do NOT add a $ at the end of the prefix pattern in the main urls.py
]
# Sub-route: app01/urls.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^reg/', views.reg)
]
# Sub-route: app02/urls.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^reg/', views.reg)
]Namespaces
# When multiple apps define routes with the same alias, reverse resolution cannot
# automatically determine the correct prefix. Namespaces solve this.
# Main urls.py
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02'))
# app01/urls.py
urlpatterns = [
url(r'^reg/', views.reg, name='reg')
]
# app02/urls.py
urlpatterns = [
url(r'^reg/', views.reg, name='reg')
]
# Backend resolution
reverse('app01:reg')
reverse('app02:reg')
# Frontend resolution (templates)
{% url 'app01:reg' %}
{% url 'app02:reg' %}
# In practice, as long as alias names don't conflict you don't need namespaces.
# A common convention is to prefix aliases with the app name:
urlpatterns = [
url(r'^reg/', views.reg, name='app01_reg')
]
urlpatterns = [
url(r'^reg/', views.reg, name='app02_reg')
]Pseudo-Static URLs
# Make a dynamic page appear to be a static page.
# The goal is to boost the site's SEO ranking.
# However, no amount of optimization beats paid advertising.
urlpatterns = [
url(r'^reg.html', views.reg, name='app02_reg')
]Virtual Environments
In normal development, each project gets its own dedicated Python interpreter
environment that contains only the packages the project actually uses.
On Linux: install only what you need, when you need it.
Virtual environments:
Creating a virtual environment is like downloading a fresh, clean Python
interpreter. Don't create too many — each one consumes disk space.
Tips:
Every project depends on many packages, often at specific versions.
How should you install them? One by one?
In development, each project ships with a requirements.txt file that lists
all required packages and their versions. A single command installs everything:
pip install -r requirements.txtLast updated on