Skip to main content

Django URL Mapping

In any web application, understanding how URLs map to content is crucial. Django's URL mapping system is powerful, flexible, and follows the DRY (Don't Repeat Yourself) principle. This guide will help you understand how Django routes incoming web requests to the appropriate view functions.

Introduction to Django URL Mapping

When a user requests a page from your Django application, Django needs to determine which Python function should handle that request. This process is called URL mapping or URL routing.

Django's URL dispatcher uses a list of URL patterns to match the requested URL and direct it to the correct view function. These patterns are defined in files called urls.py.

The URL Configuration System

The Main URLs File

In a Django project, there's a main urls.py file within your project directory. When you create a project using django-admin startproject myproject, Django generates this file automatically:

python
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
# Other URL patterns will go here
]

This is the entry point for all URL routing in your Django application.

App-Level URL Files

As your application grows, it's best to organize URLs by app:

python
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')), # Include URLs from the blog app
path('users/', include('users.urls')), # Include URLs from the users app
]

Then, in each app's directory, you create a separate urls.py file:

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

urlpatterns = [
path('', views.blog_home, name='blog-home'),
path('posts/', views.post_list, name='post-list'),
path('post/<int:post_id>/', views.post_detail, name='post-detail'),
]

The path() Function

Django's path() function is the foundation of URL mapping. Here's its basic syntax:

python
path(route, view, kwargs=None, name=None)

Let's break down each parameter:

  1. route: The URL pattern as a string.
  2. view: The view function or class that should be called when the URL matches.
  3. kwargs (optional): Additional keyword arguments to pass to the view.
  4. name (optional): A unique name for this URL pattern, used for reverse URL lookups.

Simple URL Patterns

Here's a simple example:

python
from django.urls import path
from . import views

urlpatterns = [
path('hello/', views.hello_world, name='hello-world'),
]

When a user visits /hello/, Django will call the hello_world function in views.py:

python
# views.py
from django.http import HttpResponse

def hello_world(request):
return HttpResponse("Hello, World!")

Output: When a user visits /hello/, they'll see "Hello, World!" on their browser.

URL Parameters

Django allows you to capture parts of the URL as parameters to pass to your view functions.

Path Converters

Django provides several path converters:

  • str: Matches any non-empty string, excluding the path separator (/).
  • int: Matches positive integers.
  • slug: Matches slug strings (letters, numbers, hyphens, underscores).
  • uuid: Matches UUID strings.
  • path: Matches any non-empty string, including the path separator.

Examples of URL Parameters

python
from django.urls import path
from . import views

urlpatterns = [
# Capture an integer and pass it as 'year' to the view
path('articles/<int:year>/', views.year_archive, name='article-year'),

# Capture a string and pass it as 'username' to the view
path('profile/<str:username>/', views.user_profile, name='user-profile'),

# Capture multiple parameters
path('articles/<int:year>/<int:month>/<slug:title>/',
views.article_detail,
name='article-detail'),
]

The corresponding view functions would look like this:

python
def year_archive(request, year):
# 'year' parameter is available as a function argument
articles = Article.objects.filter(pub_date__year=year)
return render(request, 'articles/year_archive.html', {'year': year, 'articles': articles})

def user_profile(request, username):
# 'username' parameter is available as a function argument
user = get_object_or_404(User, username=username)
return render(request, 'users/profile.html', {'profile_user': user})

def article_detail(request, year, month, title):
# All parameters are available as function arguments
article = get_object_or_404(Article,
pub_date__year=year,
pub_date__month=month,
slug=title)
return render(request, 'articles/detail.html', {'article': article})

Regular Expression URLs with re_path

For more complex URL patterns, Django provides re_path() which uses regular expressions:

python
from django.urls import path, re_path
from . import views

urlpatterns = [
# Match a phone number pattern
re_path(r'^phone/(\d{3})-(\d{3})-(\d{4})/$', views.phone_number),

# Match a date in YYYY-MM-DD format
re_path(r'^date/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/$', views.date_view),
]

In the view:

python
def phone_number(request, area_code, prefix, line_number):
# Positional arguments from regex groups
return HttpResponse(f"Phone: ({area_code}) {prefix}-{line_number}")

def date_view(request, year, month, day):
# Named arguments from regex groups
return HttpResponse(f"Date: {year}-{month}-{day}")

Named URLs and Reverse URL Resolution

Named URLs make it easier to refer to your URLs in templates and views:

python
path('blog/<int:post_id>/', views.post_detail, name='post-detail')

You can then generate URLs in your views:

python
from django.urls import reverse
from django.http import HttpResponseRedirect

def some_view(request):
# Redirect to a post detail page
return HttpResponseRedirect(reverse('post-detail', args=[42]))

Or in your templates:

html
<a href="{% url 'post-detail' post.id %}">Read more about {{ post.title }}</a>

Real-World Example: Blog Application

Let's bring everything together with a practical example of a simple blog application:

Project URLs

python
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include

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

Blog App URLs

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

app_name = 'blog' # Namespace for this app

urlpatterns = [
# Blog homepage showing latest posts
path('', views.post_list, name='post-list'),

# Individual post
path('post/<int:post_id>/', views.post_detail, name='post-detail'),

# Category page
path('category/<slug:category_slug>/', views.category, name='category'),

# Archive pages
path('archive/<int:year>/', views.year_archive, name='year-archive'),
path('archive/<int:year>/<int:month>/', views.month_archive, name='month-archive'),

# Author page
path('author/<str:username>/', views.author_posts, name='author-posts'),

# Search functionality
path('search/', views.search, name='search'),
]

Blog App Views

python
# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator
from .models import Post, Category

def post_list(request):
posts = Post.objects.filter(published=True).order_by('-created_at')
paginator = Paginator(posts, 10) # 10 posts per page
page = request.GET.get('page')
posts = paginator.get_page(page)
return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id, published=True)
return render(request, 'blog/post_detail.html', {'post': post})

def category(request, category_slug):
category = get_object_or_404(Category, slug=category_slug)
posts = Post.objects.filter(category=category, published=True)
return render(request, 'blog/category.html', {'category': category, 'posts': posts})

def year_archive(request, year):
posts = Post.objects.filter(created_at__year=year, published=True)
return render(request, 'blog/archive.html', {'posts': posts, 'year': year})

def month_archive(request, year, month):
posts = Post.objects.filter(
created_at__year=year,
created_at__month=month,
published=True
)
return render(request, 'blog/archive.html', {'posts': posts, 'year': year, 'month': month})

def author_posts(request, username):
posts = Post.objects.filter(author__username=username, published=True)
return render(request, 'blog/author_posts.html', {'posts': posts, 'username': username})

def search(request):
query = request.GET.get('q')
if query:
posts = Post.objects.filter(title__icontains=query, published=True)
else:
posts = Post.objects.none()
return render(request, 'blog/search.html', {'posts': posts, 'query': query})

URL Naming and Namespaces

As your project grows, you might have URL names that clash between apps. Django's namespace system solves this problem:

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

app_name = 'blog' # Define an app namespace

urlpatterns = [
path('', views.post_list, name='post-list'),
# ... more URL patterns
]

Now you can reference URLs with their namespace:

python
# In a view
from django.urls import reverse
url = reverse('blog:post-list')

# In a template
<a href="{% url 'blog:post-list' %}">Blog Home</a>

Summary

Django's URL mapping system provides:

  1. Clear URL organization with project-level and app-level URL files
  2. Flexible URL patterns through path converters and regular expressions
  3. Parameter extraction by capturing parts of the URL
  4. Named URLs for easy reference in templates and views
  5. Namespaces to prevent name collisions between apps

By mastering Django's URL system, you gain control over how users navigate through your web application and how URLs reflect your application's structure.

Additional Resources

Exercises

  1. Create a Django app with URL patterns for a book library, including routes for listing all books, viewing book details, and filtering by genre.

  2. Implement a URL pattern that captures multiple parameters, like /products/<category>/<int:product_id>/ and write the corresponding view.

  3. Create a URL pattern that accepts a date range in the format /reports/from/YYYY-MM-DD/to/YYYY-MM-DD/ using regular expressions.

  4. Practice using named URLs by creating links between different pages in your application templates.

  5. Create a URL scheme for an e-commerce site with products, categories, user profiles, and a shopping cart.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)