Comment changer un django QueryDict en Python Dict?

111

Supposons que j'ai le QueryDict suivant:

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

J'aimerais avoir un dictionnaire à partir de ceci, par exemple:

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

(Peu m'importe si le symbole Unicode ureste ou disparaît.)

Si je le fais queryDict.dict(), comme suggéré par le site django , je perds les valeurs supplémentaires appartenant à var1, par exemple:

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

Je pensais faire ceci:

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

Y a-t-il un meilleur moyen?

SaiyanGirl
la source

Réponses:

103

Cela devrait fonctionner: myDict = dict(queryDict.iterlists())

Alexandre Vassalotti
la source
4
queryDict.iterlists () crée une valeur de liste à partir de chaque clé, peut-être parce que vous affichez des listes ?, queryDict.iteritems () si vous savez que querydict ne contient pas de liste.
panchicore
3
Dans django 1.6: dict (data._iteritems ())
Bas Koopmans
5
Dans Django 1.6, dict(queryDict.lists())semble fonctionner
Dan Passaro
39
Dans Django 1.8 sur Python 3, tout ce dont j'avais besoin était dict(queryDict).
fmalina
1
Cela ne fonctionne pas pour de nombreuses bibliothèques, y compris authomatic. Voir ma question et ma propre réponse ici (fonctionne avec les v2 et v3 de python): stackoverflow.com/questions/37026535/…
Olivier Pons
194

Nouveau dans Django> = 1.4.

QueryDict.dict()

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

panchicore
la source
Deux façons de le découvrir, de l'essayer ou d'afficher la source. La réponse est non: def dict (self): "" "Renvoie l'objet actuel sous forme de dict avec des valeurs singulières." "" Return dict ((key, self [key]) for key in self)
dalore
6
Bien que cela résout le problème pour certaines personnes qui accèdent à cette page à partir de Google, cela ne répond pas à la question de OP qui demande explicitement de conserver plusieurs valeurs pour une clé.
émeute le
1
Merci mon Dieu pour cette réponse. J'étais tellement
ignorant
Travailler sur Django 1.11
Jobima
16

C'est ce que j'ai fini par utiliser:

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()}

D'après mon utilisation, cela semble vous donner une liste que vous pouvez renvoyer par exemple à un constructeur de formulaire.

EDIT: ce n'est peut-être pas la meilleure méthode. Il semble que si vous voulez par exemple écrire QueryDictdans un fichier pour une raison folle, QueryDict.urlencode()c'est la voie à suivre. Pour reconstruire le QueryDictvous faites simplement QueryDict(urlencoded_data).

Dan Passaro
la source
3
Cette méthode souffre d'un comportement indéterminé; dans une situation où une clé donnée peut avoir une ou plusieurs valeurs, vous pouvez parfois obtenir une chaîne, et parfois une liste de chaînes.
Asherah
8
from django.utils import six 
post_dict = dict(six.iterlists(request.POST))
ytyng
la source
6

Si vous ne souhaitez pas que les valeurs sous forme de tableaux, vous pouvez effectuer les opérations suivantes:

# 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 est un outil puissant pour en savoir plus ici http://docs.python.org/2/library/functions.html#zip

Krichard
la source
2
Je sais que cela a presque 6 ans, soulignant simplement pour quiconque atteint cette réponse: dans Django> = 2.0 (peut également fonctionner dans les anciennes versions, c'est juste celle que j'utilise), vous pouvez le faire QueryDict.dict()(c'est-à-dire request.POST.dict()) et cela renverra les valeurs correctement.
Luca Bezerra
Luca tu es une légende. Cela m'a rendu fou toute la journée! La vôtre est la seule réponse que je puisse trouver au travail.
scottapotamus
4

J'ai rencontré un problème similaire, souhaitant enregistrer des valeurs arbitraires d'un formulaire en tant que valeurs sérialisées.

Ma réponse évite d'itérer explicitement le contenu du dictionnaire: dict(querydict.iterlists())

Afin de récupérer une valeur de type dictionnaire qui fonctionne comme l'original, une fonction inverse utilise QueryDict.setlist()pour remplir une nouvelle QueryDictvaleur. Dans ce cas, je ne pense pas que l'itération explicite soit évitable.

Mes fonctions d'assistance ressemblent à ceci:

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
la source
3

Mettre à jour:

myDict = dict(queryDict._iterlists())

Remarque: soulignement _dans la méthode iterlists de queryDict. Version de Django: 1.5.1

Parthyz
la source
3

dict(request.POST) renvoie un dictionnaire python étrange avec des valeurs enveloppées dans un tableau.

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

où as {x:request.POST.get(x) for x in request.POST.keys()}renvoie la sortie attendue.

{'start': '2017-01-14T21:00', 'stop': '2017-01-14T22:00', 'email': '[email protected]'}
Sandeep
la source
Dans Django> = 2.0 (peut également fonctionner dans les anciennes versions, c'est juste celui que j'utilise), vous pouvez le faire QueryDict.dict()(c'est-à-dire request.POST.dict()) et il retournera les valeurs correctement.
Luca Bezerra
2

ajoutez simplement

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

Dans votre vue et les données seront enregistrées dans querDict en tant que python Dict.

omkar yadav
la source
1

Voici comment j'ai résolu ce problème:

dict_ = {k: q.getlist(k) if len(q.getlist(k))>1 else v for k, v in q.items()}
mbijou
la source
1

Comme moi, vous êtes probablement plus familier avec les Dict()méthodes en python. Cependant, le QueryDict()est également un objet facile à utiliser. Par exemple, vous souhaitiez peut-être obtenir la valeur du fichier request.GET QueryDict().

Vous pouvez le faire comme ceci: request.GET.__getitem__(<key>).

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

Marquistador
la source
1
Évitez d'utiliser les méthodes de double soulignement. La manière la plus pythonique serait d'utiliser request.GET.get(<key>)ourequest.GET.getlist(<key>)
Bobort
1

Avec Django 2.2il existe peu de solutions propres:

  1. QueryDict.dict()est le plus simple mais il cassera QueryDictavec des listes comme valeurs, par exemple:
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)

sortira

a two  # <--- missed 'one'
b three
  1. dict(QueryDict) est mieux car il fera un dictionnaire correct des listes:
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)

sortira

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

qui est correct.

Valex
la source
0

J'ai essayé les deux dict(request.POST)et request.POST.dict()et j'ai réalisé que si vous aviez des listvaleurs par exemple 'var1':['value1', 'value2']imbriquées dans votre request.POST, le later ( request.POST.dict()) ne me donnait accès qu'au dernier élément d'une liste imbriquée tandis que l'ancien ( dict(request.POST)) me permettait d'accéder à tous les éléments d'une liste imbriquée.

J'espère que ça aidera quelqu'un.

Codebender
la source