Django Reverse URL – reverse() function

Managing URLs in Django can become very cumbersome if you don’t employ the right tactic in the beginning. Imagine that you have to deal with thousands of hardcoded URLs and know which one to use for each situation. To make it easier, the Django reverse() function can be used.

In short, the Django reverse function is used to transform a view name given to the URL pattern into an actual URL. A quick example of usage is shown below.

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

def example_view(request):
    return HttpResponseRedirect(reverse('named-url'))

Django reverse() function explained

When resolving incoming requests, Django tries to match the URL pattern (URL -> view name), then picks the right view and generates a response. 

But when you need to go another way around, you’ll want to pick a view and build an appropriate URL out of it (view name -> URL). For that purpose, you can use the django.urls.reverse function. The main point of using this function is to avoid hardcoding URLs which keeps you from breaking your application if you decide to change URL paths in the future.

The reverse() function is commonly used in pair with the redirect logic. You can learn more about redirects in our Django Redirect Explained post.

Let’s see what the function constructor looks like.

reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)

  • viewname – name of the view (URL pattern name) or the callable view object for which the URL will be generated.
  • urlconf – URLconf module containing the URL patterns to use for reversing.
  • args – arguments if URL accepts them.
  • kwargs – keyword-arguments if URL accepts them.
  • current_app – application to which the currently executing view belongs.

Examples of Django reverse() function usage

In this section, we’ll show how to use the reverse() function:

  • without additional arguments and parameters,
  • with args,
  • with kwargs

Using Django reverse() function without additional arguments

To make it clear what our URL patterns look like, let’s take a sneak peek into urls.py.

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

urlpatterns = [
    path('/original-url/', views.original_view),
    path('/another-url/', views.another_view, name='named-url')
]

Now if we want to use the original-url/ to redirect the request to the another-url/ we can define the logic inside the original_view (in the views.py). Here we pass the named-url string to the reverse() function to point to the correct view.

# views.py
from django.urls import reverse
from django.http import HttpResponseRedirect

def original_view(request):
    # line below is an example of how you SHOULD NOT hardcode a URL
    # return HttpResponseRedirect('/another-url/')
    reversed_url = reverse('named-url')  # /another-url/
    return HttpResponseRedirect(reversed_url)

Another way of correct usage is by passing the callable view object as the first argument. In the example below, we are passing the another_view as a function argument.

# views.py
from django.urls import reverse
from django.http import HttpResponse, HttpResponseRedirect

def another_view(request):
    content = '<p>dummy content</p>'
    return HttpResponse(content)

def original_view(request):
    reversed_url = reverse(another_view)  # /another-url/
    return HttpResponseRedirect(reverse(another_view))
NOTE - If no match can be made, reverse() function will raise the NoReverseMatch exception.

Using reverse() function with args

Sometimes you’ll have a URL pattern that expects an additional parameter. You can notice in the urls.py that the another-url/ has an additional parameter defined, which allows it to look like any of the following URL paths: another-url/dummy/, another-url/123/, etc.

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

urlpatterns = [
    path('/original-url/', views.original_view),
    path('/another-url/<some_arg>/', views.another_view, name='named-url')
]

To reverse the view into a URL, inside the views.py we need to somehow tell the Django that the URL expects an additional argument. We do that by passing the args list as an additional argument to the reverse() function constructor. Doing this will reverse with arguments, constructing a full URL path.

# views.py
from django.urls import reverse
from django.http import HttpResponseRedirect

def original_view(request):
    reversed_url = reverse('named-url', args=[123])  # /another-url/123/
    return HttpResponseRedirect(reversed_url)

Using reverse() function with kwargs

Similarly, sometimes you’ll need to construct a URL that expects additional key-value parameters. In the urls.py you can see what such a URL pattern looks like.

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

urlpatterns = [
    path('/original-url/', views.original_view),
    path(r'/another-url/<arg1>/<arg2/', views.another_view, name='named-url')
]

To reverse with additional kwargs arguments, we need to pass the kwargs object as an additional argument to the reverse() function constructor. Doing this will construct a full URL path taking into consideration a kwargs object.

# views.py
from django.urls import reverse
from django.http import HttpResponseRedirect

def original_view(request):
    reversed_url = reverse('named-url', kwargs={'arg1':123, 'arg2':'dummy'})  # /another-url/123/dummy/
    return HttpResponseRedirect(reversed_url)

Django reverse_lazy() function

If you need a URL reversal before your project’s URLconf is loaded, you can use the django.urls.reverse_lazy function. It is a lazily evaluated version of reverse()

This function is commonly used in generic class-based views. Take a look at the following example.

# views.py
from django.urls import reverse, reverse_lazy
from django.views.generic import CreateView

class CreateItemView(CreateView):
    # success_url = reverse_lazy('named-url')

    def get_success_url(self, **kwargs):
        return reverse('named-url')

As you can see, we presented two ways of defining a success URL. The first one is by using the success_url attribute directly inside the CreateItemView class. This attribute will be evaluated exactly at the moment the class itself is imported; therefore we must use the lazily evaluated version.

On the other hand, if we build the success URL by using the get_success_url function, then we can use the reverse() function because it will be evaluated exactly when it’s called.