Django中reverse()和reverse_lazy()的区别

57

我知道在FBV中可以使用reverse(),而在CBV中可以使用reverse_lazy()。 我们必须在CBV中使用reverse_lazy(),因为在导入文件时未加载URL(参考:Reverse_lazy and URL Loading?

我不明白的是:

当我们从FBV调用reverse时,URL如何加载? 因为在Django应用程序的urls.py顶部导入视图时,urlpatterns列表尚未被评估。 reverse()如何适用于FBV,但不适用于CBV?

7个回答

63

考虑以下两种定义success_url的方式。第一种已经被注释掉了,第二种是函数:

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 :你说得对,类属性在导入时就会被评估,在阅读了你的回答后我进行了检查。因此,

  1. 如果我们使用success_url,我们必须使用reverse_lazy()
  2. 如果我们在函数内部反转,我们可以使用reverse()

现在一切都很清楚了。

谢谢,CoffeeBasedLifeform :)


2
有使用 reverse 的理由吗?只需始终使用 reverse_lazy,不必担心 URL 是否已加载。reverse 有什么好处吗? - Sviatozar Petrenko

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

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

>>> import importme
>>> CLASS HELLO

编辑: 原因: 类的创建过程涉及执行类的主体。

类主体执行为exec(body, globals(), namespace)。[...] 一旦通过执行类主体填充了类名称空间,就通过调用metaclass(name, bases, namespace, **kwds)创建类对象。

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



原始回答文本。您可以忽略它 - 我只是保留它,因为mirek的评论是对它的直接回应:

导入时计算类属性。关于何时以及如何发生,这取决于Python的导入系统的深度。


4
它位于Python的导入系统深处--我认为它存在于类的原则中,而不是“深度中...”。定义的类必须具有其属性。 - mirek

16

Reverse_lazy是反向URL解析器的一种惰性实现,顾名思义。与传统的反向函数不同,只有在需要值时,reverse_lazy才会执行。

它很有用,因为在处理可能不会立即知道的URL时可以防止反向未找到(Reverse Not Found)异常。

为什么我们需要它? 因为类属性在导入时被计算,在那个时候 Reverse方法将返回'Reverse Not Found'。 稍后需要时,在其执行时,所有必要的代码片段已经被执行,以给出有效的URL。


5

理解它们之间的区别:

reverse() 返回一个 字符串,而 reverse_lazy() 返回一个 <对象>


2
这怎么解释这种奇怪的行为?真心问问。 - Kwaku Biney
请将以下关于编程的内容从英语翻译成中文。仅返回翻译后的文本。详见:https://dev59.com/bVYM5IYBdhLWcg3wlQwi#75653186 - Guzman Ojero

5

区别:

  1. 在函数中使用reverse(),在类中使用reverse_lazy()。
  2. reverse()返回一个字符串,而reverse_lazy()返回一个对象。

2

reversereverse_lazy函数的目标相同:根据输入(如命名URL)生成URL。

它们之间的区别在于评估时间:

  • reverse用于在调用函数或方法时生成URL。

让我们举个例子:

一个函数:

#views.py

from django.urls import reverse

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

reverse函数在调用my_view函数时被评估:它生成一个命名为url-name的URL,并将整数1作为参数传递。

一种方法:

#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})

再次强调,reverse函数在调用get_absolute_url方法时被评估。

在这两种情况下重要的是,在调用reverse函数时,它已经具有URLConf的信息,因此可以轻松找到url模式。

  • reverse_lazy也用于生成URL,但它推迟了评估的时刻,直到实际需要为止。这就是它是reverse的惰性评估版本的原因。

你可能会想知道为什么...

在代码中有时需要使用URL反转,但不确定URLConf是否已加载。 如果在URLConf尚未加载时使用reverse,则会出现错误。

这个错误是因为反向解析需要知道项目中定义的URLConf URL模式,以便生成正确的URL。如果URLConf没有被加载,reverse将无法找到生成URL所需的信息,并引发异常。

例如:

一个基于类的视图

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

当您定义success_url一个类属性)时,您使用了reverse_lazy而不是reverse这是因为类属性在执行类定义时进行评估。这意味着分配给类属性的值是在定义类时确定的,而不是在创建类的实例时确定的。

当您导入类时,Python解释器会从上到下执行类定义,包括类属性,如success_url,但有可能URLConf尚未加载。

为了避免错误,我们使用reverse_lazy而不是reverse,它将实际调用URLConf的时间延迟到需要的时候,而不是在评估类属性时。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接