【问题标题】:What is reverse()?什么是反向()?
【发布时间】:2012-06-29 19:08:35
【问题描述】:

当我有时阅读 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 很好的解释,谢谢。这个名字对我来说似乎(并且似乎)特别不直观,我认为这是一个严重的罪过。谁不讨厌不必要的混淆?
  • 这是一个典型的命名示例,它强调实体(例如函数)的一个方面,考虑到他的上下文,这在当时程序员的头脑中是最重要的,但不是最有用的选项在任何其他开发人员的广泛背景下。作为程序员,我们经常落入这个陷阱——命名对于可发现性非常重要,值得停下来思考不同的上下文并选择最合适的上下文。

标签: django


【解决方案1】:

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 的需求。处理这些怪事的最好方法是拒绝使用它们。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    现有的答案很清楚。万一你不知道为什么叫reverse:它接受一个url名称的输入并给出实际的url,这与先有一个url然后给它一个名字是相反的。

    【讨论】:

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

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

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

    正如其他人所提到的,一个关键的好处是 URL 的反向构造。就像您如何使用 {% url "profile" profile.id %} 从您的应用程序的 url 配置文件中生成 url 一样:例如path('&lt;int:profile.id&gt;/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 字符串的优雅方法(@987654338 @ 由 URLConfig 处理)。假设question 有一个属性id 包含值5,那么从reverse() 构造的URL 将是:

    '/polls/5/results/'
    

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

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

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

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

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

    【讨论】:

      【解决方案5】:

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

      来自官方文档:

      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 特别提到他阅读了文档,他需要解释,而不仅仅是从文档中复制/粘贴。
      【解决方案6】:

      有一个文档

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

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

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

      【讨论】:

        【解决方案7】:

        该功能支持干原则 - 确保您不会在整个应用程序中对网址进行硬编码。一个 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。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-24
          • 1970-01-01
          • 2016-11-11
          • 2015-06-16
          • 1970-01-01
          • 1970-01-01
          • 2021-12-08
          • 1970-01-01
          相关资源
          最近更新 更多