Можно ли упорядочить заказ Django QueryDict?

Возможно ли сделать QueryDict Django сохранением заказа из исходной строки запроса?

>>> 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' 

    3 Solutions collect form web for “Можно ли упорядочить заказ Django QueryDict?”

    QueryDict наследует от QueryDict от Django, который наследует от dict который реализован как хеш-таблица . Таким образом, вы не можете гарантировать, что он будет оставаться заказанным.

    Я не уверен, что это будет иметь отношение к тому, что вам нужно, но заказ, который QueryDict сохраняет, – это порядок «списков» (несколько значений для одного и того же ключа), переданных им . Используя это, вы можете сделать:

     >>> 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' 

    Класс QueryDict основан на классе MultiValueDict который основан на регулярном python dict , который является неупорядоченной коллекцией, как вы знаете.

    Согласно исходному коду QueryDict внутренне использует 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 и метод override 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[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' 

    Этот подход немного уродлив и может нуждаться в дальнейшем улучшении, но, надеюсь, по крайней мере, он даст вам представление о том, что происходит и что вы можете с этим поделать.

    Возвращаясь к этому вопросу почти через 3 года, я понял, что мы можем тривиально сделать QueryDict который сохраняет упорядочение по зависимостям, впрыскивая collections.OrderedDict как бэкенд отображения:

     >>> class MyQueryDict(QueryDict, OrderedDict): ... pass ... >>> QueryDict(u'x=1&y=2&z=3').urlencode() u'y=2&x=1&z=3' >>> MyQueryDict(u'x=1&y=2&z=3').urlencode() u'x=1&y=2&z=3' 

    Он работает, потому что super делегаты в соответствии с MRO , поэтому MyQueryDict должен прокси-серверу для OrderedDict для хранения вместо использования обычного Python dict .

     >>> QueryDict.__mro__ (django.http.request.QueryDict, django.utils.datastructures.MultiValueDict, dict, object) >>> MyQueryDict.__mro__ (__main__.MyQueryDict, django.http.request.QueryDict, django.utils.datastructures.MultiValueDict, collections.OrderedDict, # <-- new kid on the block! dict, object) 
    Python - лучший язык программирования в мире.