我可以让Django QueryDict保持排序吗?

时间:2014-05-14 18:22:43

标签: python django http query-string

是否可以让Django的QueryDict保留原始查询字符串的排序?

>>> from django.http import QueryDict
>>> q = QueryDict(u'x=foo³&y=bar(potato),z=hello world')
>>> q.urlencode(safe='()')
u'y=bar(potato)%2Cz%3Dhello%20world&x=foo%C2%B3'

2 个答案:

答案 0 :(得分:2)

QueryDict继承自Django的MultiValueDict,继承自dict implemented as a hash table。因此,您不能保证它会保持订购。

我不确定这是否与您的需求相关,但an ordering that QueryDict does preserve is the order of "lists" (multiple values for the same key) passed in to them。使用它,你可以这样做:

>>> from django.http import QueryDict
>>> q = QueryDict(u'x=foo³&x=bar(potato),x=hello world')
>>> q.lists()
[('x', ['foo³', 'bar(potato)', 'hello world'])]
>>> q.urlencode(safe='()')
u'x=foo%C2%B3&x=bar(potato)&x=hello%20world'

答案 1 :(得分:1)

QueryDict类基于MultiValueDict类,该类基于常规python dict,如您所知,这是一个无序集合。

根据source codeQueryDict内部使用urlparse.parse_qsl()方法,该方法保留查询参数的顺序,输出元组列表:

>>> from urlparse import parse_qsl
>>> parse_qsl('x=foo³&y=bar(potato),z=hello world')
[('x', 'foo\xc2\xb3'), ('y', 'bar(potato),z=hello world')]

您可以做的是使用parse_qsl()给出的键的顺序进行排序:

>>> order = [key for key, _ in parse_qsl('x=foo³&y=bar(potato),z=hello world')]
>>> order
['x', 'y']

然后,子类QueryDict并覆盖lists()中使用的urlencode()方法:

>>> class MyQueryDict(QueryDict):
...     def __init__(self, query_string, mutable=False, encoding=None, order=None):
...         super(MyQueryDict, self).__init__(query_string, mutable=False, encoding=None)
...         self.order = order
...     def lists(self):
...         return [(key, self.getlist(key)) for key in self.order]
... 
>>> q = MyQueryDict(u'x=foo³&y=bar(potato),z=hello world', order=order)
>>> q.urlencode(safe='()')
u'x=foo%C2%B3&y=bar(potato)%2Cz%3Dhello%20world'

这种方法有点难看,可能需要进一步改进,但希望至少它会让你了解正在发生的事情以及你可以采取的措施。

相关问题