Django使用reverse()重定向到依赖查询字符串的URL

Django redirect using reverse() to a URL that relies on query strings

我正在编写一个带有\\'http:// localhost / entity / id /?overlay = other_id \\'这样的URL的Django应用程序。其中id是特定实体的主键,而overlay是要在显示中覆盖的第二个实体的可选查询参数。通过叠加层查看对象时,用户只能更新实体。当发布到/ update / id时,我想重定向回/ entity / id,但是我不想在重定向过程中丢失查询参数,因为视图中的更改会令人讨厌。

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

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

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

1
2
3
4
5
6
7
return HttpResponseRedirect(
  reverse('views.view',
    kwargs={
      'id': id,
    },
  )
)

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

谢谢Craig


您可以使用Django QueryDict对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
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()

当然,您可以为其编写一个方便的方法,类似于先前的答案。


您不能只检查一个overlay_id并将其添加到您的URL吗?

1
2
3
4
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 )


查询字符串args应该正确地转义,而不仅仅是连接!

通过字符串连接使用查询字符串构建url与通过字符串连接构建SQL查询一样是个坏主意。使用用户提供的(不受信任的)输入时,它是复杂的,模糊的,尤其危险。不幸的是Django无法将查询参数传递给反向函数。

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

在我的应用程序中,我创建了一个帮助器这样的功能:

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

然后在视图中按如下方式调用它:

1
2
3
4
5
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字符串。给定您的urls.py,您可以使用以下方式进行反向操作:

1
2
3
4
5
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",))

如果您使用命名的URL模式,则非常适合将视图函数与URL标识符断开连接:

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

使用像这样反向:

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