Frage Kann ich Django QueryDict beibehalten, um die Reihenfolge beizubehalten?


Ist es möglich, Djangos QueryDict die Reihenfolge aus der ursprünglichen Abfragezeichenfolge beizubehalten?

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

8
2018-05-14 18:22


Ursprung


Antworten:


QueryDict erbt von Djangos MultiValueDict was erbt von dict welches ist als Hash-Tabelle implementiert. Somit können Sie nicht garantieren, dass es bestellt bleibt.

Ich bin mir nicht sicher, ob das für das relevant ist, was Sie brauchen, aber Eine Reihenfolge, die von QueryDict beibehalten wird, ist die Reihenfolge von "Listen" (mehrere Werte für denselben Schlüssel), die an sie übergeben wurden. Mit diesem könnten Sie tun:

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

2
2018-05-14 19:04



QueryDict Klasse basiert auf MultiValueDict Klasse, die auf regulären Python basiert dict, das ist eine ungeordnete Sammlung, wie Sie wissen.

Entsprechend der Quellcode, QueryDict intern verwendet urlparse.parse_qsl() Methode, die die Reihenfolge der Abfrageparameter beibehält, gibt eine Liste von Tupeln aus:

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

Was Sie tun können, ist die Reihenfolge der Schlüssel zu verwenden, die von der parse_qsl() zum Sortieren:

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

Dann, Unterklasse QueryDict und überschreiben lists() Methode verwendet in 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'

Der Ansatz ist ein bisschen hässlich und könnte weitere Verbesserungen erfordern, aber hoffe zumindest, dass es dir eine Vorstellung davon geben wird, was passiert und was du dagegen tun kannst.


1
2018-05-14 19:20



Zurück zu dieser Frage, fast 3 Jahre später, habe ich gemerkt, dass wir trivialerweise eine machen können QueryDict was die Ordnung durch Abhängigkeitsinjektion erhält a collections.OrderedDict als Mapping-Backend:

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

Es funktioniert, weil super Delegierte nach dem MRO, damit MyQueryDict muss sich an die OrderedDict für die Speicherung anstelle der regulären 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)

0
2018-01-23 02:46