URL Configuration Basics
URLconf is Django's URL routing system. It maps URL patterns to views. When a request comes in, Django runs through the URL patterns from top to bottom until it finds a match, then calls the corresponding view.
Your project has a root URL configuration, and each app can have its own. This modular approach keeps URL routing organized as your project grows.
from django.urls import path
from . import views
urlpatterns = [
path('', views.home_view, name='home'),
path('about/', views.about_view, name='about'),
path('contact/', views.contact_view, name='contact'),
]
Each entry in urlpatterns maps a URL pattern to a view function. The name parameter lets you reference this URL from templates and code.
Capturing URL Parameters
URL patterns can capture dynamic values. Use angle brackets to capture parameters and pass them to your view.
from django.urls import path
from . import views
urlpatterns = [
path('posts/<int:post_id>/', views.post_detail, name='post_detail'),
path('users/<str:username>/', views.user_profile, name='user_profile'),
path('archive/<int:year>/<int:month>/', views.archive, name='archive'),
]
Django provides path converters like int, str, slug, and uuid to capture and validate URL parameters automatically.
Using include() and Namespaces
As your project grows, putting all URLs in one file becomes unwieldy. The include() function lets you split URL configurations across multiple apps.
from django.urls import path, include
urlpatterns = [
path('blog/', include('blog.urls')),
path('accounts/', include('accounts.urls')),
path('admin/', admin.site.urls),
]
Each app defines its own urlpatterns. Namespaces let you avoid URL name collisions between apps. If both apps have a 'detail' URL, you can use blog:detail and accounts:detail to distinguish them.
Reversing URLs
Hardcoding URLs in templates and views is a bad idea. If you change a URL pattern, you'd have to find and update every reference. Instead, use the name parameter to reverse URLs.
from django.urls import reverse
def post_list(request):
url = reverse('post_detail', kwargs={'post_id': 1})
return redirect(url)
In templates, use the {% url %} tag for the same purpose.
{% url 'post_detail' post_id=post.id %}
{% url 'user_profile' username=user.username %}
Always use named URLs. It makes your code more maintainable and lets you change URL patterns without breaking existing links.
Using re_path() for Complex Patterns
When path() isn't flexible enough, re_path() lets you use regular expressions for URL matching.
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^articles/(?P<year>\d{4})/$', views.article_year),
re_path(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.article_month),
]
Regex patterns give you full control over URL matching, but they're harder to read. Use path() when it covers your needs, and re_path() only when you need regex flexibility.