Jak zmienić django QueryDict na Python Dict?

111

Załóżmy, że mam następujący QueryDict:

<QueryDict: {u'num': [0], u'var1': [u'value1', u'value2'], u'var2': [u'8']}>

Chciałbym mieć z tego słownik, np .:

{'num': [0], 'var1':['value1', 'value2'], 'var2':['8']}

(Nie obchodzi mnie, czy symbol Unicode upozostaje, czy znika).

Jeśli to zrobię queryDict.dict(), jak sugeruje strona django , stracę dodatkowe wartości należące do var1np .:

{'num': [0], 'var1':['value2'], 'var2':['8']}

Myślałem o zrobieniu tego:

myDict = {}
for key in queryDict.iterkeys():
    myDict[key] = queryDict.getlist(key)

Czy jest lepszy sposób?

SaiyanGirl
źródło

Odpowiedzi:

103

To powinno działać: myDict = dict(queryDict.iterlists())

Alexandre Vassalotti
źródło
4
queryDict.iterlists () tworzy wartość listy z każdego klucza, być może dlatego, że widzisz listy ?, queryDict.iteritems (), jeśli wiesz, że querydict nie zawiera listy.
panchicore,
3
W django 1.6: dict (data._iteritems ())
Bas Koopmans
5
dict(queryDict.lists())Wydaje się , że w Django 1.6 działa
Dan Passaro,
39
W Django 1.8 na Pythonie 3 wszystko, czego potrzebowałem, to dict(queryDict).
fmalina
1
To nie działa w przypadku wielu bibliotek, w tym automatycznych. Zobacz moje pytanie i moją własną odpowiedź tutaj (działa z v2 i v3 w Pythonie): stackoverflow.com/questions/37026535/ ...
Olivier Pons
194

Nowość w Django> = 1.4.

QueryDict.dict()

https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.QueryDict.dict

panchicore
źródło
Dwa sposoby, aby się tego dowiedzieć, wypróbować lub wyświetlić źródło. Odpowiedź brzmi: nie: def dict (self): "" "Zwraca bieżący obiekt jako dict z wartościami osobliwymi." "" Return dict ((key, self [key]) for key in self)
dalore
6
Chociaż rozwiązuje to problem niektórych osób, które odwiedzają tę stronę z Google, nie odpowiada to na pytanie OP, które wyraźnie prosi o zachowanie wielu wartości dla klucza.
zamieszkał
1
Dzięki Bogu za tę odpowiedź. Nie miałem pojęcia
Nic Wanavit
Praca nad Django 1.11
jobima
16

Oto, co ostatecznie użyłem:

def qdict_to_dict(qdict):
    """Convert a Django QueryDict to a Python dict.

    Single-value fields are put in directly, and for multi-value fields, a list
    of all values is stored at the field's key.

    """
    return {k: v[0] if len(v) == 1 else v for k, v in qdict.lists()}

Z mojego doświadczenia wynika, że ​​otrzymujesz listę, którą możesz odesłać np. Do konstruktora formularzy.

EDYCJA: może to nie jest najlepsza metoda. Wydaje się, że jeśli chcesz np. Pisać QueryDictdo pliku z jakiegoś szalonego powodu, QueryDict.urlencode()jest to najlepszy sposób. Aby zrekonstruować to, QueryDictco po prostu robisz QueryDict(urlencoded_data).

Dan Passaro
źródło
3
Ta metoda cierpi z powodu nieokreślonego zachowania; w sytuacji, gdy dany klucz może mieć jedną lub więcej wartości, czasami można uzyskać ciąg znaków, a czasami listę łańcuchów.
Asherah
8
from django.utils import six 
post_dict = dict(six.iterlists(request.POST))
ytyng
źródło
6

Jeśli nie chcesz, aby wartości były tablicami, możesz wykonać następujące czynności:

# request = <QueryDict: {u'key': [u'123ABC']}>
dict(zip(request.GET.keys(), request.GET.values()))
{u'key': u"123ABC" }

# Only work for single item lists
# request = <QueryDict: {u'key': [u'123ABC',U 'CDEF']}>
dict(zip(request.GET.keys(), request.GET.values()))
{u'key': u"CDEF" } 

zip to potężne narzędzie. Przeczytaj więcej na ten temat tutaj http://docs.python.org/2/library/functions.html#zip

krichard
źródło
2
Wiem, że to ma prawie 6 lat, po prostu wskazując każdemu, kto dotrze do tej odpowiedzi: W Django> = 2.0 (może działać również w starszych wersjach, to tylko ta, której używam), możesz to zrobić QueryDict.dict()(tj. request.POST.dict()) I to zwróci wartości poprawnie.
Luca Bezerra
Luca, jesteś legendą. To doprowadza mnie do szału przez cały dzień! Twoja jest jedyną odpowiedzią, jaką mogę zabrać do pracy.
scottapotamus
4

Napotkałem podobny problem, chcąc zapisać dowolne wartości z formularza jako wartości serializowane.

Moja odpowiedź unika jawnego iterowania zawartości słownika: dict(querydict.iterlists())

Aby pobrać wartość podobną do słownika, która działa jak oryginał, funkcja odwrotna używa QueryDict.setlist()do wypełnienia nowej QueryDictwartości. W tym przypadku nie sądzę, aby można było uniknąć wyraźnej iteracji.

Moje funkcje pomocnicze wyglądają tak:

from django.http import QueryDict

def querydict_dict(querydict):
    """
    Converts a Django QueryDict value to a regular dictionary, preserving multiple items.
    """
    return dict(querydict.iterlists())

def dict_querydict(dict_):
    """
    Converts a value created by querydict_dict back into a Django QueryDict value.
    """
    q = QueryDict("", mutable=True)
    for k, v in dict_.iteritems():
        q.setlist(k, v)
    q._mutable = False
    return q
Graham Klyne
źródło
3

Aktualizacja:

myDict = dict(queryDict._iterlists())

Uwaga: podkreślenie _w iterlists metoda queryDict. Wersja Django: 1.5.1

Parthyz
źródło
3

dict(request.POST) zwraca dziwny słownik Pythona z wartościami opakowanymi w tablicę.

{'start': ['2017-01-14T21:00'], 'stop': ['2017-01-14T22:00'], 'email': ['[email protected]']}

gdzie jak {x:request.POST.get(x) for x in request.POST.keys()}zwraca oczekiwany wynik.

{'start': '2017-01-14T21:00', 'stop': '2017-01-14T22:00', 'email': '[email protected]'}
Sandeep
źródło
W Django> = 2.0 (może działać również w starszych wersjach, to tylko ta, której używam), możesz to zrobić QueryDict.dict()(tj. request.POST.dict()) I zwróci wartości poprawnie.
Luca Bezerra
2

po prostu dodaj

queryDict=dict(request.GET) lub queryDict=dict(QueryDict)

W Twoim widoku dane zostaną zapisane w querDict jako python Dict.

omkar yadav
źródło
1

Oto jak rozwiązałem ten problem:

dict_ = {k: q.getlist(k) if len(q.getlist(k))>1 else v for k, v in q.items()}
mbijou
źródło
1

Podobnie jak ja, prawdopodobnie lepiej znasz Dict()metody w Pythonie. Jednak QueryDict()jest to również obiekt łatwy w użyciu. Na przykład, być może chcesz uzyskać wartość z pliku request.GET QueryDict().

Można to zrobić w taki sposób: request.GET.__getitem__(<key>).

QueryDict()dokumentacja: https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.QueryDict

Marquistador
źródło
1
Unikaj stosowania metod z podwójnym podkreśleniem. Bardziej pytonicznym sposobem byłoby użycie request.GET.get(<key>)orrequest.GET.getlist(<key>)
Bobort
1

Ze Django 2.2istnieje kilka czystych rozwiązań:

  1. QueryDict.dict()jest najprostszy, ale zepsuje QueryDictlisty jako wartości, np .:
from django.http.request import QueryDict, MultiValueDict

query_dict = QueryDict('', mutable=True)
query_dict.update(MultiValueDict({'a': ['one', 'two']}))
query_dict.update({'b': 'three'})

for key, value in query_dict.dict().items():  # ---> query_dict.dict()
    print(key, value)

wyjdzie

a two  # <--- missed 'one'
b three
  1. dict(QueryDict) jest lepszy, ponieważ poprawi słownik list:
from django.http.request import QueryDict, MultiValueDict

query_dict = QueryDict('', mutable=True)
query_dict.update(MultiValueDict({'a': ['one', 'two']}))
query_dict.update({'b': 'three'})

for key, value in dict(query_dict).items():  # ---> dict(query_dict)
    print(key, value)

wyjdzie

a ['one', 'two']
b ['three']

który jest poprawny.

valex
źródło
0

Wypróbowałem oba dict(request.POST)i request.POST.dict()zdałem sobie sprawę, że jeśli masz listwartości na przykład 'var1':['value1', 'value2']zagnieżdżone w swojej request.POST, późniejsza ( request.POST.dict()) dała mi dostęp tylko do ostatniej pozycji na zagnieżdżonej liście, podczas gdy pierwsza ( dict(request.POST)) pozwoliła mi uzyskać dostęp do wszystkich pozycji na liście zagnieżdżonej.

Mam nadzieję, że to komuś pomoże.

Codebender
źródło