ChatGPT解决这个技术问题 Extra ChatGPT

什么是反向()?

当我有时阅读 Django 代码时,我会在一些模板中看到 reverse()。我不太确定这是什么,但它与 HttpResponseRedirect 一起使用。这个 reverse() 应该如何以及何时使用?

给定一个 url 模式,Django 使用 url() 来选择正确的视图并生成一个页面。即url--> view name。但有时,比如重定向时,你需要反方向走,给 Django 一个视图的名称,Django 会生成相应的 url。换句话说,view name --> url。即 reverse() (与 url 函数相反)。将其称为 generateUrlFromViewName 似乎更透明,但这太长而且可能不够通用:docs.djangoproject.com/en/dev/topics/http/urls/…
@neuronet 很好的解释,谢谢。这个名字对我来说似乎(并且似乎)特别不直观,我认为这是一个严重的罪过。谁不讨厌不必要的混淆?
这是一个典型的命名示例,它强调实体(例如函数)的一个方面,考虑到他的上下文,这在当时程序员的脑海中是最重要的,但在任何其他开发人员的广泛上下文中并不是最有用的选择.作为程序员,我们经常陷入这个陷阱——命名对于可发现性非常重要,值得停下来思考不同的上下文并选择最合适的上下文。

S
Sabito 錆兎 stands with Ukraine

reverse() | Django documentation

假设您在 urls.py 中定义了这个:

url(r'^foo$', some_view, name='url_name'),

然后,您可以在模板中将此 url 引用为:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

这将呈现为:

<a href="/foo/">link which calls some_view</a>

现在假设您想在 views.py 中执行类似的操作 - 例如,您正在其他视图(不是 some_view)中处理其他 URL(不是 /foo/)并且您希望将用户重定向到 /foo/(通常成功提交表单的案例)。

你可以这样做:

return HttpResponseRedirect('/foo/')

但是,如果您将来想更改 URL 怎么办?您必须在您的代码中更新您的urls.py 所有对它的引用。这违反了 DRY (Don't Repeat Yourself) 原则和仅在一个地方进行编辑的整个想法 - 这是值得努力的事情。

相反,你可以说:

from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))

这会在您的项目中定义的所有 URL 中查找以名称 url_name 定义的 URL,并返回实际的 URL /foo/

这意味着您仅通过其 name 属性来引用 URL - 如果您想要更改 URL 本身或它所引用的视图,您可以通过仅编辑一个位置来执行此操作 - urls.py


仅供参考,在 Django 1.4 或更早版本中,{{ url 'url_name' }} 应该是 {% url url_name %}。这将在下一个 Django 版本 (1.5) 中更改,然后应该是 {% url 'url_name' %}。如果您向下滚动到“向前兼容性”部分,url templatetag 的文档会提供一些很好的信息
j_syk 谢谢 - 自 1.3 发布以来,我一直在做 @load url from future@ 并忘记它还不是默认值。我会更新我的答案,所以它不会绊倒没有经验的人。
不要太挑剔,并继续以不绊倒没有经验的人为主题,但它应该是块标签 {% %} 而不是可变标签 {{ }} 用于 url 标签 :)
已修复-我认为您自己编辑其他人的答案中的愚蠢错别字是完全可以接受的,因此如果您看到更多内容,请直接加入:-)
“>>>但是如果你以后想更改网址怎么办”,这些微妙之处在 0.0001% 的时间里很有用,而且解决方案就像一个有用的功能一样发布,人们使用它就好像它们是“最佳实践”并留下混乱。 TBH,如果将来有人更改网址时,您只需进行全局查找替换。即使这种解决方案(使用 url_name)也容易出现“如果您以后想更改 url_name 怎么办?”的问题。已经在 Django 中编码超过 5 年,但尚未满足对 url_reverse 的需求。处理这些怪事的最好方法是拒绝使用它们。
y
yyFred

现有的答案很清楚。以防万一您不知道为什么将其称为 reverse:它需要输入一个 url 名称并给出实际的 url,这与先有一个 url 然后给它一个名称相反。


刚刚从教程(Django Girls)中学习 Django。这是一个陡峭的学习曲线。我认为这个函数的名字很可怕:没有任何限定的“保留”非常强烈建议保留一个列表或字符串,这显然与它无关。
@mikerodent 我完全同意你的看法。此外,这些答案都没有解释为什么该函数被称为反向。这是一个糟糕的名字imo。
o
onlyphantom

现有答案很好地解释了 Django 中这个 reverse() 函数的什么

但是,我希望我的回答能对 why 有不同的看法:为什么在模板中使用 reverse() 代替其他更直接、可以说更 Python 的方法 -视图绑定,以及这种“重定向 via reverse() 模式”在 Django 路由逻辑中流行的一些正当理由。

正如其他人所提到的,一个关键的好处是 URL 的反向构造。就像您如何使用 {% url "profile" profile.id %} 从应用的 url 配置文件生成 url:例如 path('<int:profile.id>/profile', views.profile, name="profile")

但正如 OP 所指出的,reverse() 的使用也通常与 HttpResponseRedirect 的使用结合使用。但为什么?

我不太确定这是什么,但它与 HttpResponseRedirect 一起使用。这个 reverse() 应该如何以及何时使用?

考虑以下 views.py

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

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected = question.choice_set.get(pk=request.POST['choice'])
    except KeyError:
        # handle exception
        pass
    else:
        selected.votes += 1
        selected.save()
        return HttpResponseRedirect(reverse('polls:polls-results',
                                    args=(question.id)
        ))

还有我们最小的 urls.py

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('<int:question_id>/results/', views.results, name='polls-results'),
    path('<int:question_id>/vote/', views.vote, name='polls-vote')
]

vote() 函数中,我们的 else 块中的代码使用 reverseHttpResponseRedirect,模式如下:

HttpResponseRedirect(reverse('polls:polls-results',
                                        args=(question.id)

这首先意味着我们不必对 URL 进行硬编码(与 DRY 原则一致),但更重要的是,reverse() 提供了一种通过处理从参数中解包的值来构造 URL 字符串的优雅方式(处理 args=(question.id)通过 URLConfig)。假设 question 具有包含值 5 的属性 id,则从 reverse() 构造的 URL 将是:

'/polls/5/results/'

在普通的模板视图绑定代码中,我们使用 HttpResponse()render(),因为它们通常涉及较少的抽象:一个视图函数返回一个模板:

def index(request):
    return render(request, 'polls/index.html') 

但在许多合法的重定向案例中,我们通常关心从参数列表构造 URL。这些包括以下情况:

通过 POST 请求提交 HTML 表单

用户登录后验证

通过 JSON Web 令牌重置密码

其中大多数涉及某种形式的重定向,以及通过一组参数构造的 URL。希望这增加了已经有帮助的答案线程!


m
mc_kaiser

这是一个老问题,但这里有一些可能对某人有帮助的东西。

来自官方文档:

Django 提供了用于执行 URL 反转的工具,这些工具与需要 URL 的不同层相匹配: 在模板中:使用 url 模板标签。在 Python 代码中:使用 reverse() 函数。在与处理 Django 模型实例的 URL 相关的更高级别代码中: get_absolute_url() 方法。

例如。在模板中(url 标签)

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

例如。在 python 代码中(使用 reverse 函数)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

需要完整的描述老板
OP 特别提到他阅读了文档,他需要解释,而不仅仅是从文档中复制/粘贴。
A
Ashish Kumar Sahoo

该函数支持干原则 - 确保您不会在整个应用程序中对 url 进行硬编码。一个 url 应该在一个地方定义,而且只有一个地方 - 你的 url conf。之后,您实际上只是在引用该信息。

使用 reverse() 为您提供页面的 url,给定视图的路径或 url conf 中的 page_name 参数。如果在模板中使用 {% url 'my-page' %} 执行此操作没有意义,则可以使用它。

您可以在很多地方使用此功能。我发现我使用它的一个地方是在视图中重定向用户时(通常在成功处理表单之后) -

return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))

您也可以在编写模板标签时使用它。

我使用 reverse() 的另一次是模型继承。我在父模型上有一个 ListView,但想从这些父对象中的任何一个获取它的关联子对象的 DetailView。我向父级附加了一个 get__child_url() 函数,该函数标识了一个子级的存在,并使用 reverse() 返回了它的 DetailView 的 url。


e
eric

有一个文档

https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls

它可用于为给定视图生成 URL

主要优点是您不会在代码中对路由进行硬编码。


S
Samsul Islam

reverse() 用于遵守 django DRY 原则,即如果您将来更改 url,那么您可以使用 reverse(urlname) 引用该 url。