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)