DEV Community


Posted on • Originally published at

Difference between reverse() and reverse_lazy() in Django

Both reverse and reverse_lazy functions have the same objective: to generate a URL based on the inputs (like a named url).

The difference is in when they are evaluated:

  • reverse is used to generate a URL at the time the function or method is called.

Let's put an example:

A function:

    from django.urls import reverse

    def my_view(request):
        url = reverse('url-name', args=[1])
        # do something with the URL
Enter fullscreen mode Exit fullscreen mode

The reverse function is evaluated at the moment the my_view function is called: it generates a URL for the named url url-name, passing the integer 1 as an argument.

A method: 

    from django.db import models

    class Post(models.Model):
        #rest of the class

        def get_absolute_url(self):
            return reverse("blog:post_detail", kwargs={"pk":})
Enter fullscreen mode Exit fullscreen mode

Again, the reverse function is evaluated at the moment the get_absolute_url method is called.

What is important in both this cases is that at the moment the reverse function is called, it already has the information of the URLConf, so it can easily find the url pattern.

  • reverse_lazy is also used to generate a URL, but it defers the moment of evaluation until it is actually needed. That's way it is a lazily evaluated version of reverse.

You may be wondering why...

There are moments in your code when you need to use a URL reversal, but you don't exactly know if the URLConf has already been loaded.

If you use reverse when the URLConf hasn't already been loaded, you would get an error.

This error occurs because reverse needs to know the URL patterns defined in the project's URLConf in order to generate the correct URL. If the URLConf has not been loaded, reverse will not be able to find the necessary information to generate the URL and will raise an exception.


A class based view:

    from django.views.generic.edit import DeleteView
    from django.urls import reverse_lazy

    class PostDeleteView(DeleteView):
       model = Post
       template_name = "post_delete.html"
       success_url = reverse_lazy('home')
Enter fullscreen mode Exit fullscreen mode

When you defined the success_url (a class attribute) you used reverse_lazy instead of reverse.

This is because class attributes are evaluated at the time when the class definition is executed.

This means that the values assigned to class attributes are determined when the class is defined, and not when instances of the class are created.

When you import the class, the Python interpreter executes the class definition from top to bottom and that includes the class atrtributes like success_url, but there are chances that the URLConf hadn't been loaded.

To not have an error, instead of using reverse we use reverse_lazy, which delays the actual call to the URLConf to the moment is needed and not when the class attribute is evaluated.

NOTE: originally posted in StackOverflow

Top comments (0)