Django Dynamic URL Patterns

Django Dynamic URL Patterns

Being able to capture one or more values from a given URL during an HTTP request is an important feature Django offers developers. We already saw a little bit about how Django routing works, but those examples used hard-coded URL patterns. While this does work, it does not scale. Consider a website that has thousands of pages. You don’t necessarily need thousands of routes to serve those pages, but you do need the ability to capture variables from the URL so that one route pattern can handle many different pages. In this tutorial, we’ll explore a little bit more about Dynamic URL Patterns and values in Django.


Angle Brackets < >

To capture a value in the URL pattern, you can use angle brackets. Below we have the hard-coded URL Patterns from the prior tutorial, and how we can rewrite three routes into one using angle brackets.

Hard-Coded URL Routes

C:\python\djangoprojects\myproject\goals\urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('daily', views.daily),
    path('weekly', views.weekly),
    path('monthly', views.monthly),
]

Rewritten Using Angle Brackets

C:\python\djangoprojects\myproject\goals\urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('<timeframe>', views.goals_by_timeframe),
]

By using angle brackets, we are essentially defining a variable for whatever is between the opening < and closing >. So in the snippet just above, timeframe is now a variable.

Pass Captured Value(s) To View Function

Now that we understand how to capture a value from the URL, what can we actually do with it? Well if you capture a variable value, now you likely want to pass that value into a function and examine its contents to make decisions on what action to take next. In the snippet above, the path defined points to a goals_by_timeframe() function in the views.py file. We can pass the captured timeframe variable to that function by passing it as the second argument. Let’s see that code here.

C:\python\djangoprojects\myproject\goals\views.py

from django.shortcuts import render
from django.http import HttpResponse


def goals_by_timeframe(request, timeframe):
    return HttpResponse(f'The timeframe is {timeframe}')

We can see now that the goals_by_timeframe() function accepts two arguments. The first is the request itself, and the second is the timeframe variable that we defined in urls.py. As a quick test, we can simply return the value contained in the timeframe variable right back to the web browser. Now whatever value is contained in the URL at that specific location, will be captured and returned to the browser. Let’s see that in action.

django dynamic url one


django dynamic url two


dynamic url django three

Adding View Logic

In the old hard-coded views.py file, we had three different functions to handle the different timeframes. Now we only have one function, so we need to add some logic and conditional checking into that function so that it can respond with the correct information based on the value of the timeframe variable. Here is a refactored version of goals_by_timeframe() that does just that.

C:\python\djangoprojects\myproject\goals\views.py

from django.shortcuts import render
from django.http import HttpResponse


def goals_by_timeframe(request, timeframe):
    if timeframe == 'daily':
        goals = 'Daily Goals'
    elif timeframe == 'weekly':
        goals = 'Weekly Goals'
    elif timeframe == 'monthly':
        goals = 'Monthly Goals'
    else:
        return HttpResponse('No Goals Found')
    return HttpResponse(goals)

This function can now respond with the correct data when the timeframe is either daily, weekly, or monthly. If we don’t pass in one of those three values, we let the user know that no goals were found.

django dynamic view logic


django captured value


django second argument view function


There are no goals found when passing in a timeframe of quarterly, and that is what we would expect based on the code above.

django captured value url


Dynamic Segments With Path Converters

When we refer to dynamic segments, it is the value in between angle brackets in urls.py.

django dynamic segment

Since this dynamic segment is magically turned into a variable, that means it also has a type. But what type does it have? By default, Django uses the str path converter. In other words, captured values are strings. This is true even if you enter a numeric value as part of the captured segment. We can examine the captured type using this snippet.

C:\python\djangoprojects\myproject\goals\views.py

from django.shortcuts import render
from django.http import HttpResponse


def goals_by_timeframe(request, timeframe):
    print(type(timeframe))
    return HttpResponse(timeframe)

Now we can examine the console as a GET request is made. Here we see ‘weekly’ is the captured value, and note it is of type str in the console output.

django captured value type
django type dynamic segment

What about if there is a number like ‘7’ as the captured value? This also shows as a str.
django number as str in url
django url num to str

We can tell Django that we actually want a number value to act as an integer rather than a string. We can use the path converter <int:timeframe> like so.

C:\python\djangoprojects\myproject\goals\urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('<int:timeframe>', views.goals_by_timeframe),
]

With that addition, a captured number in the URL now is used as an actual integer.

number captured value django
django cast num to int url

The str and int path converters cover almost all use cases. Django does also offer slug, uuid, and path as path converters.

Learn More About Django Dynamic URL Patterns

The URL Dispatch docs have everything you need to know to work with URLs and captured values in Django.