什么是Django中的reverse()


218

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

如果有人给出一些例子的答案是件好事...


26
给定一个url模式,Django使用url()选择正确的视图并生成一个页面。即url--> view name。但是有时,例如在重定向时,您需要反向操作并为Django提供视图名称,然后Django会生成适当的url。换句话说,view name --> url。也就是说,reverse()(与url函数相反)。仅仅调用它似乎更透明,generateUrlFromViewName但这太长了,可能还不够通用:docs.djangoproject.com/en/dev/topics/http/urls/…–
eric

4
@neuronet很好的解释,谢谢。这个名字在我看来(和似乎)特别不直观,我认为这是严重的罪过。谁不讨厌不必要的混淆?
麦克啮齿动物'18年

这是一个典型的命名示例,它强调了一个实体(例如函数)的一个方面,这是当时程序员最先想到的,因为给定了他的上下文,但是在任何其他开发人员的广泛上下文中,这都不是最有用的选择。作为程序员,我们经常会陷入这一陷阱-命名对于发现能力非常重要,值得停下来思考一下不同的上下文并选择最合适的上下文。
Cornel Masson

Answers:


345

reverse()| Django文档


假设urls.py您已经定义了以下内容:

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

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

<!-- 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-例如,您正在/foo/其他视图(不是some_view)中处理其他URL(不是),并且您想要将用户重定向到/foo/(通常是成功提交表单时)。

您可以这样做:

return HttpResponseRedirect('/foo/')

但是,如果您以后想更改网址怎么办?您必须在代码中更新您urls.py 及其所有引用。这违反了DRY(请勿重复自己),即只编辑一个位置的整个想法,这是我们要努力的目标。

相反,您可以说:

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

这将在项目中定义的所有url中查找使用name定义的url url_name并返回实际的url /foo/

这意味着您只能通过其name属性来引用url- 如果要更改url本身或它所引用的视图,则只能通过编辑一个位置来进行此操作- urls.py


2
仅供参考,{{ url 'url_name' }}应该{% url url_name %}在Django 1.4或更早的版本中。这将在下一个Django版本(1.5)中更改,然后应为{% url 'url_name' %}。如果您向下滚动到“前向兼容性”部分,则url templatetag的文档会提供一些很好的信息
j_syk 2012年

1
j_syk谢谢-自1.3推出以来,我一直在执行@ future @ load url,但忘记了它不是默认值。我将更新我的答案,以免遇到新手。
scytale 2012年

2
已修正-我认为您自己编辑别人的答案中的愚蠢错字完全可以接受,因此,如果您看到更多内容,请直接跳进:-)
scytale 2012年

3
在此站点上可以找到的最微妙的答案之一。
Manas Chaturvedi 2015年

1
“ >>>但是如果将来要更改url,该怎么办呢?”,这种微妙的用法在.0001%的时间内有用,解决方案像有用的功能一样在交付,人们就好像在使用'最佳做法”,不要乱七八糟。TBH,如果将来更改网址时,您只需要全局查找即可。即使此解决方案(使用url_name)也容易出现“如果将来要更改url_name怎么办?”的问题。在Django中进行编码已有5年了,但仍未满足对Django的需要url_reverse。处理此类奇怪情况的最佳方法是拒绝使用它们。
nehem

10

这是一个古老的问题,但这可能会对某人有所帮助。

从官方文档:

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

1
需要完整的描述老板
GiveJob

OP特别提到他阅读了文档,他需要解释,而不仅仅是从文档中复制/粘贴。
RusI

8

现有的答案在解释做了伟大的工作,什么 这个的reverse()在Django功能。

但是,我希望我的答案能解释一个不同的原因:为什么reverse()在模板视图绑定中使用其他更简单,可以说是更多python方式的方法,以及这种“ 通过 reverse()模式”)。

正如其他人提到的那样,一个主要好处是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有一个id包含value 的属性,5则从构造的URL reverse()将是:

'/polls/5/results/'

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

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

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

  • 通过POST请求提交HTML表单
  • 用户登录后验证
  • 通过JSON Web令牌重置密码

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


4

该函数支持干式原则-确保您不会在整个应用中硬编码网址。网址应在一个地方定义,并且只能在一个地方定义-您的网址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()为父级附加了一个函数,该函数标识了子级的存在,并使用返回了其DetailView的url reverse()



2

现有的答案很明确。以防万一,您不知道为什么要调用reverse它:它接受一个URL名称的输入并给出实际的URL,这与首先拥有一个URL然后再给它一个名称相反。


1
只是从教程(Django Girls)中学习Django。这是一个陡峭的学习曲线。我认为此函数的名称令人恐惧:“保留”没有任何限定非常强烈地建议保留列表或字符串,这显然与它无关。
麦克啮齿动物

@mikerodent我完全同意你的看法。此外,这些答案都不能解释为什么将函数称为反向。imo真是个坏名字。
Soham Dongargaonkar

1

reverse()用于遵循Django DRY原理,即,如果将来更改URL,则可以使用reverse(urlname)引用该URL。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.