【问题标题】:Django redirect using reverse() to a URL that relies on query stringsDjango 使用 reverse() 重定向到依赖于查询字符串的 URL
【发布时间】:2011-05-27 11:59:27
【问题描述】:

我正在编写一个 django 应用程序,其 URL 类似于“http://localhost/entity/id/?overlay=other_id”。其中 id 是特定实体的主键,overlay 是要在显示中覆盖的第二个实体的可选查询参数。用户只能在通过叠加层查看对象时更新实体。当 POST 到 /update/id 时,我想重定向回 /entity/id,但我不想在重定向期间丢失我的查询参数,因为视图的变化会很不协调。

例如,我的 url.py 中有以下内容:

...
(r'^update/(?P<id>.+)/(?P<overlay_id>.+)/$', 'update'),
(r'^entity/(?P<id>.+)/$', 'view'),
...

因为更新时需要overlay_id,所以它是URL 的一部分,而不是查询参数。在 django 视图中,我想在 POST 成功后重定向并使用 reverse() 来避免在我的 python 代码中引用 URL。总体思路是:

return HttpResponseRedirect(
  reverse('views.view',
    kwargs={
      'id': id,
    },
  )
)

但是如何通过反向传递我的查询参数?

谢谢, 克雷格

【问题讨论】:

    标签: django django-views


    【解决方案1】:

    您可以使用Django QueryDict object

    from django.http import QueryDict
    
    # from scratch
    qdict = QueryDict('',mutable=True)
    
    # starting with our existing query params to pass along
    qdict = request.GET.copy()
    
    # put in new values via regular dict
    qdict.update({'foo':'bar'})
    
    # put it together
    full_url = reversed_url + '?' + qdict.urlencode()
    

    当然,您可以为它编写一个类似于上一个答案的便捷方法。

    【讨论】:

    • update() 会将值附加到查询字符串中,因此任何现有的 'foo' 值都将保留而不是被替换。如果要替换任何现有值,请使用qdict['foo'] = 'bar'
    【解决方案2】:

    您不能只检查overlay_id 并将其添加到您的网址吗?

    redirect_url = reverse( ... )
    extra_params = '?overlay=%s' % overlay_id if overlay_id else ''
    full_redirect_url = '%s%s' % (redirect_url, extra_params)
    return HttpResponseRedirect( full_redirect_url )
    

    【讨论】:

    • 是的,我在一秒钟前刷牙时意识到了这一点。有时我希望 Python 有类型签名,因为如果将 reverse() 声明为返回字符串,这将是显而易见的。谢谢。
    • 我通常会在第二天早上洗澡时得到那些啊哈时刻。您可能会发现 pdb(或 ipdb)在您需要类型签名的情况下会有所帮助。尝试一段时间将import pdb; pdb.set_trace() 放入您的代码中。 docs.python.org/library/pdb.html
    【解决方案3】:

    查询字符串 args 应正确转义,而不仅仅是串联!

    通过字符串连接构建带有查询字符串的 url 与通过字符串连接构建 SQL 查询一样糟糕。对于用户提供的(不受信任的)输入,它是复杂的、不优雅的并且特别危险。不幸的是,Django 无法将查询参数传递给reverse 函数。

    Python 标准 urllib 然而提供了所需的查询字符串编码功能。

    在我的application 中,我创建了一个这样的辅助函数:

    def url_with_querystring(path, **kwargs):
        return path + '?' + urllib.urlencode(kwargs)
    

    那我在视图中调用如下:

    quick_add_order_url = url_with_querystring(reverse(order_add),
        responsible=employee.id, scheduled_for=datetime.date.today(),
        subject='hello world!')
    # http://localhost/myapp/order/add/?responsible=5&
    #     scheduled_for=2011-03-17&subject=hello+world%21
    

    请注意空格和感叹号等特殊字符的正确编码!

    【讨论】:

    • 无需自己费心为查询字符串参数进行url编码。 HTTPResponseRedirect 将为您完成。
    • @Declan Shanaghy HTTPResponseRedirect 不提供任何查询字符串组装功能(django 文档:“构造函数采用单个参数——重定向到的路径。”),所以你必须自己做。但不是使用 istruble 建议的简单字符串连接 - 这不适用于包含特殊字符或空格的值。
    【解决方案4】:

    您不应该自己生成 url 字符串。鉴于您的 urls.py,您可以像这样使用 reverse:

    from django.core.urlresolvers import reverse
    print reverse('view_function_name', kwargs={"id":"id_value", "overlay_id": "overlay_id_value"})
    
    # or to pass view function arguments as an array:
    print reverse('view_function_name', args=("id_value","overlay_id_value",))
    

    如果您使用named url patterns,这非常适合将您的视图功能与 url 标识符断开:

    # urls.py
    ...
    (r'^update/(?P<id>.+)/(?P<overlay_id>.+)/$', 'update', name="update_foo"),
    ...
    

    像这样使用反向:

    print reverse("update_foo", kwargs={"id":"id_value", "overlay_id": "overlay_id_value"})
    

    【讨论】:

    • 这里有no_way单引号和双引号有什么区别。
    • 除了我在 3 月 27 日那天的经历之外,我想根据您的评论编辑我的答案。其他人可以确认吗?
    • 在某个情况下,您可能忘记了字符串开头的“r”(或“r”:))。不是在这些示例中,而是在您使用 \d 之类的其他示例中,缺少 'r' 将使 python 将 \d (和其他)解释为特殊字符,而不是将它们留给 RE 引擎查找.这是我能想到的最好的猜测。如果您确实可以找到不起作用的语句 - 在修复它之前 - 我们可以对其进行分析。
    • 我已经编辑了我的答案以消除引用混淆。谢谢 Ch'marr
    猜你喜欢
    • 2022-03-24
    • 2014-11-03
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    • 2012-11-29
    • 2021-04-05
    • 1970-01-01
    相关资源
    最近更新 更多