Difference between reverse() and reverse_lazy() in Django

Question:

I understand that we can use reverse() in FBV and reverse_lazy() in CBV. I understand that we have to use reverse_lazy() in CBV as the urls are not loaded when the file is imported (Ref: Reverse_lazy and URL Loading?)

What I don’t understand is:

How are the urls loaded when we call reverse from the FBV? As when we import the views at the top of the urls.py in a Django app, urlpatterns list is yet to be evaluated. How does reverse() for FBV work but not for CBV?

Asked By: RyuCoder

||

Answers:

#importme.py
def a():
    print("FUNCTION HELLO")

class B():
    print("CLASS HELLO") 
    

>>> import importme
>>> CLASS HELLO

Edit:
The reason: The class creation process involves executing the body of the class.

The class body is executed (approximately) as exec(body, globals(), namespace). […] Once the class namespace has been populated by
executing the class body, the class object is created by calling
metaclass(name, bases, namespace, **kwds).

https://docs.python.org/3/reference/datamodel.html?highlight=metaclass#executing-the-class-body



My original answer text. You can ignore it – I’m just leaving it in because mirek’s comment was a direct response to it:

Class attributes are evaluated on import. The answer to when or exactly how that happens, resides within the depths of python’s import system.

Answered By: CoffeeBasedLifeform

Consider these two ways of defining the success_url. The first is commented out,
the second is the function:

class NewJobCBV(LoginRequiredMixin, CreateView):
    template_name = 'company/job.html'
    form_class = newJobForm
    # success_url = reverse_lazy('newJob')

    def get_success_url(self, **kwargs):
        return reverse("newJob")

@CoffeeBasedLifeform : you are right, class attributes are evaluated on import, I checked after reading your answer. So,

  1. If we are using success_url we have to use reverse_lazy().
  2. If we are reversing inside a function we can use reverse().

Now it is crystal clear.

Thanks CoffeeBasedLifeform 🙂

Answered By: RyuCoder

Because: Python class attributes are evaluated on the declaration.
Please read this link: Python class attributes are…

Answered By: Milad Hatami

Just understand the difference:

reverse() returns a string & reverse_lazy() returns an <object>

Answered By: shoaib21

Reverse_lazy is, as the name implies, a lazy implementation of the reverse URL resolver. Unlike the traditional reverse function, reverse_lazy won’t execute until the value is needed.

It is useful because it prevent Reverse Not Found exceptions when working with URLs that may not be immediately known.

Why do we need it?
It’s needed because, Class attributes are evaluated on import and at that time Reverse method will return ‘Reverse Not Found’.
Later upon need, at the time of its execution, all the necessary code snippets will be executed already, to give a valid URL.

Answered By: Usman Maqsood

difference:

  1. reverse() use in funcation & reverse_lazy() use in class.
  2. reverse() use in string & reverse_lazy() use in object
Answered By: BiswajitPaloi

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:

#views.py

from django.urls import reverse

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

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:

#models.py 

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": self.pk})

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.

Example:

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')

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.

Answered By: Guzman Ojero