Skip to main content

URLs

URL Configuration Basics

Project URLs

# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls')),
path('api/', include('myapp.api.urls')),
path('blog/', include('blog.urls')),
path('accounts/', include('django.contrib.auth.urls')),
]

# Serve media files in development
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

App URLs

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

app_name = 'myapp'

urlpatterns = [
path('', views.index, name='index'),
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
path('articles/', views.article_list, name='article_list'),
path('articles/<slug:slug>/', views.article_detail, name='article_detail'),
path('articles/create/', views.article_create, name='article_create'),
path('articles/<int:pk>/edit/', views.article_edit, name='article_edit'),
path('articles/<int:pk>/delete/', views.article_delete, name='article_delete'),
]

URL Patterns

Basic Patterns

from django.urls import path
from . import views

urlpatterns = [
# Static URL
path('', views.index, name='index'),
path('about/', views.about, name='about'),

# URL with string parameter
path('user/<str:username>/', views.profile, name='profile'),

# URL with integer parameter
path('article/<int:pk>/', views.article_detail, name='article_detail'),

# URL with slug parameter
path('category/<slug:slug>/', views.category_detail, name='category_detail'),

# URL with UUID parameter
path('item/<uuid:uuid>/', views.item_detail, name='item_detail'),
]

Path Converters

from django.urls import path
from . import views

urlpatterns = [
# String (default) - matches any string excluding '/'
path('user/<str:username>/', views.user_profile, name='user_profile'),

# Integer - matches positive integers
path('article/<int:id>/', views.article_detail, name='article_detail'),

# Slug - matches slug strings (letters, numbers, hyphens, underscores)
path('category/<slug:slug>/', views.category_detail, name='category_detail'),

# UUID - matches UUID strings
path('item/<uuid:item_id>/', views.item_detail, name='item_detail'),

# Path - matches any string including '/'
path('file/<path:filepath>/', views.file_detail, name='file_detail'),
]

Custom Path Converters

# converters.py
class YearMonthConverter:
regex = r'[0-9]{4}-[0-9]{2}'

def to_python(self, value):
year, month = value.split('-')
return {'year': int(year), 'month': int(month)}

def to_url(self, value):
return f"{value['year']:04d}-{value['month']:02d}"

# urls.py
from django.urls import path, register_converter
from . import views
from .converters import YearMonthConverter

register_converter(YearMonthConverter, 'yearmonth')

urlpatterns = [
path('archive/<yearmonth:date>/', views.archive, name='archive'),
]

Regular Expressions

Using re_path

from django.urls import re_path
from . import views

urlpatterns = [
# Basic regex
re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive, name='year_archive'),

# Multiple parameters
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',
views.month_archive, name='month_archive'),

# Optional parameters
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',
views.day_archive, name='day_archive'),

# Case-insensitive
re_path(r'^(?i)about/$', views.about, name='about'),

# File extensions
re_path(r'^files/(?P<filename>[\w\-_]+)\.(?P<extension>txt|pdf|doc)$',
views.file_download, name='file_download'),
]

Complex Regex Patterns

from django.urls import re_path
from . import views

urlpatterns = [
# Email validation
re_path(r'^user/(?P<email>[\w\.-]+@[\w\.-]+\.\w+)/$',
views.user_by_email, name='user_by_email'),

# Date formats
re_path(r'^events/(?P<date>\d{4}-\d{2}-\d{2})/$',
views.events_by_date, name='events_by_date'),

# Phone numbers
re_path(r'^contact/(?P<phone>\+?1?-?\(?[0-9]{3}\)?-?[0-9]{3}-?[0-9]{4})/$',
views.contact_by_phone, name='contact_by_phone'),

# API versioning
re_path(r'^api/v(?P<version>[1-9]\d*)/', include('api.urls')),
]

URL Namespacing

App Namespaces

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

app_name = 'myapp'

urlpatterns = [
path('', views.index, name='index'),
path('detail/<int:pk>/', views.detail, name='detail'),
]

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

app_name = 'blog'

urlpatterns = [
path('', views.index, name='index'),
path('post/<int:pk>/', views.post_detail, name='detail'),
]

Instance Namespaces

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

urlpatterns = [
path('admin-blog/', include('blog.urls', namespace='admin-blog')),
path('public-blog/', include('blog.urls', namespace='public-blog')),
]

URL Reversal

Reverse in Views

from django.urls import reverse
from django.shortcuts import redirect

def my_view(request):
# Simple reverse
url = reverse('myapp:index')

# Reverse with arguments
url = reverse('myapp:detail', args=[1])
url = reverse('myapp:detail', kwargs={'pk': 1})

# Reverse with namespace
url = reverse('admin:index')

# Redirect using reverse
return redirect('myapp:detail', pk=1)

Reverse in Templates

<!-- Simple URL -->
<a href="{% url 'myapp:index' %}">Home</a>

<!-- URL with arguments -->
<a href="{% url 'myapp:detail' pk=article.pk %}">{{ article.title }}</a>
<a href="{% url 'myapp:detail' article.pk %}">{{ article.title }}</a>

<!-- URL with query parameters -->
<a href="{% url 'myapp:search' %}?q=django&category=web">Search</a>

<!-- URL with namespace -->
<a href="{% url 'admin:index' %}">Admin</a>

Reverse with Query Parameters

from django.urls import reverse
from urllib.parse import urlencode

def my_view(request):
base_url = reverse('myapp:search')
query_params = urlencode({'q': 'django', 'category': 'web'})
url = f"{base_url}?{query_params}"

return redirect(url)

URL Patterns Organization

Including URL Patterns

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

urlpatterns = [
path('', include('home.urls')),
path('blog/', include('blog.urls')),
path('shop/', include('shop.urls')),
path('api/v1/', include('api.v1.urls')),
]

# Multiple includes
urlpatterns = [
path('', include([
path('', include('home.urls')),
path('about/', include('about.urls')),
])),
]

URL Pattern Lists

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

# Group related URLs
article_patterns = [
path('', views.article_list, name='article_list'),
path('<int:pk>/', views.article_detail, name='article_detail'),
path('create/', views.article_create, name='article_create'),
path('<int:pk>/edit/', views.article_edit, name='article_edit'),
path('<int:pk>/delete/', views.article_delete, name='article_delete'),
]

user_patterns = [
path('profile/', views.profile, name='profile'),
path('settings/', views.settings, name='settings'),
path('password/', views.change_password, name='change_password'),
]

urlpatterns = [
path('articles/', include(article_patterns)),
path('user/', include(user_patterns)),
]

URL Utilities

URL Building

from django.urls import reverse
from django.utils.http import urlencode

def build_url(view_name, args=None, kwargs=None, query_params=None):
url = reverse(view_name, args=args, kwargs=kwargs)
if query_params:
url += '?' + urlencode(query_params)
return url

# Usage
url = build_url('myapp:search', query_params={'q': 'django', 'page': 2})

URL Validation

from django.urls import resolve, reverse, NoReverseMatch
from django.urls.exceptions import Resolver404

def validate_url(url_path):
try:
resolve(url_path)
return True
except Resolver404:
return False

def validate_reverse(view_name, args=None, kwargs=None):
try:
reverse(view_name, args=args, kwargs=kwargs)
return True
except NoReverseMatch:
return False

Error Handling

Custom Error Pages

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

handler404 = 'myapp.views.custom_404'
handler500 = 'myapp.views.custom_500'
handler403 = 'myapp.views.custom_403'
handler400 = 'myapp.views.custom_400'

urlpatterns = [
# Your URL patterns
]

Error Views

# views.py
from django.shortcuts import render

def custom_404(request, exception):
return render(request, 'errors/404.html', status=404)

def custom_500(request):
return render(request, 'errors/500.html', status=500)

def custom_403(request, exception):
return render(request, 'errors/403.html', status=403)

def custom_400(request, exception):
return render(request, 'errors/400.html', status=400)

URL Debugging

URL Resolution

from django.urls import resolve

def debug_url(request):
resolver_match = resolve(request.path)
return {
'view_name': resolver_match.view_name,
'args': resolver_match.args,
'kwargs': resolver_match.kwargs,
'namespace': resolver_match.namespace,
'app_name': resolver_match.app_name,
}

URL Patterns Inspection

from django.urls import get_resolver

def list_urls():
resolver = get_resolver()

def extract_patterns(urlpatterns, namespace=''):
patterns = []
for pattern in urlpatterns:
if hasattr(pattern, 'url_patterns'):
patterns.extend(extract_patterns(
pattern.url_patterns,
namespace + pattern.namespace + ':'
))
else:
patterns.append((namespace + pattern.name, pattern.pattern))
return patterns

return extract_patterns(resolver.url_patterns)

Performance Optimization

URL Caching

from django.urls import path
from django.views.decorators.cache import cache_page
from . import views

urlpatterns = [
path('', cache_page(60 * 15)(views.index), name='index'),
path('static-page/', cache_page(60 * 60)(views.static_page), name='static_page'),
]

URL Compilation

# Pre-compile regex patterns for better performance
import re
from django.urls import re_path

YEAR_PATTERN = re.compile(r'[0-9]{4}')
MONTH_PATTERN = re.compile(r'[0-9]{2}')

urlpatterns = [
re_path(r'^archive/(?P<year>' + YEAR_PATTERN.pattern + ')/$',
views.year_archive, name='year_archive'),
]

Security Considerations

URL Security

# Avoid exposing sensitive information in URLs
urlpatterns = [
# Bad: exposes user ID
path('user/<int:user_id>/', views.user_detail, name='user_detail'),

# Good: use slug or UUID
path('user/<slug:username>/', views.user_detail, name='user_detail'),
path('user/<uuid:user_uuid>/', views.user_detail, name='user_detail'),
]

URL Validation in Views

from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required

@login_required
def user_detail(request, username):
# Ensure user can only access their own profile
if request.user.username != username and not request.user.is_staff:
return HttpResponseForbidden()

user = get_object_or_404(User, username=username)
return render(request, 'user_detail.html', {'user': user})

Testing URLs

URL Testing

from django.test import TestCase
from django.urls import reverse, resolve

class URLTest(TestCase):
def test_url_reverse(self):
url = reverse('myapp:index')
self.assertEqual(url, '/')

def test_url_resolve(self):
resolver = resolve('/')
self.assertEqual(resolver.view_name, 'myapp:index')

def test_url_with_parameters(self):
url = reverse('myapp:detail', kwargs={'pk': 1})
self.assertEqual(url, '/detail/1/')

def test_url_response(self):
response = self.client.get(reverse('myapp:index'))
self.assertEqual(response.status_code, 200)