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.