Como mudar um django QueryDict para Python Dict?

111

Vamos fingir que tenho o seguinte QueryDict:

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

Eu gostaria de ter um dicionário fora disso, por exemplo:

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

(Não me importo se o símbolo Unicode upermanece ou se vai.)

Se o fizer queryDict.dict(), conforme sugerido pelo site django , perco os valores extras pertencentes a var1, por exemplo:

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

Eu estava pensando em fazer isso:

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

Existe uma maneira melhor?

SaiyanGirl
fonte

Respostas:

103

Isso deve funcionar: myDict = dict(queryDict.iterlists())

Alexandre Vassalotti
fonte
4
queryDict.iterlists () está criando um valor de lista de cada chave, talvez porque você espectadores de listas ?, queryDict.iteritems () se você souber que querydict não contém lista.
panchicore
3
No Django 1.6: dict (data._iteritems ())
Bas Koopmans
5
No Django 1.6, dict(queryDict.lists())parece funcionar
Dan Passaro
39
No Django 1.8 em Python 3 tudo que eu precisava era dict(queryDict).
fmalina
1
Isso não funciona para muitas bibliotecas, incluindo o Authomatic. Veja minha pergunta e minha própria resposta aqui (funciona com v2 e v3 de python): stackoverflow.com/questions/37026535/…
Olivier Pons
193

Novo no Django> = 1.4.

QueryDict.dict()

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

Panchicore
fonte
Duas maneiras de descobrir, experimentar ou ver a fonte. A resposta é não: def dict (self): "" "Retorna o objeto atual como um dict com valores singulares." "" Return dict ((key, self [key]) for key in self)
dalore
6
Embora isso resolva o problema para algumas das pessoas que vêm do google para esta página, não responde à pergunta de OP, que pede explicitamente a retenção de vários valores para uma chave.
tumultuado em
1
Graças a Deus por esta resposta. Eu estava tão sem noção
Nic Wanavit
Trabalhando no Django 1.11
jobima
16

Isso é o que acabei usando:

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

Pelo meu uso, isso parece lhe dar uma lista que você pode enviar de volta, por exemplo, um construtor de formulário.

EDIT: talvez este não seja o melhor método. Parece que se você deseja, por exemplo, gravar QueryDictem um arquivo por qualquer motivo maluco, QueryDict.urlencode()é o caminho a seguir. Para reconstruir o que QueryDictvocê simplesmente faz QueryDict(urlencoded_data).

Dan Passaro
fonte
3
Este método sofre de comportamento indeterminado; em uma situação em que uma determinada chave pode ter um ou mais valores, às vezes você pode obter uma string e, às vezes, uma lista de strings.
Asherah
8
from django.utils import six 
post_dict = dict(six.iterlists(request.POST))
ytyng
fonte
6

Se você não quiser os valores como Arrays, pode fazer o seguinte:

# 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 é uma ferramenta poderosa, leia mais sobre ela aqui http://docs.python.org/2/library/functions.html#zip

Krichard
fonte
2
Eu sei que isso tem quase 6 anos, apenas apontando para quem chegar a esta resposta: Em Django> = 2.0 (pode funcionar em versões mais antigas também, é só o que estou usando), você pode fazer QueryDict.dict()(ie request.POST.dict()) e retornará os valores corretamente.
Luca Bezerra
Luca você é uma lenda. Isso tem me deixado louco o dia todo! A sua é a única resposta que consigo fazer funcionar.
scottapotamus
4

Eu tive um problema semelhante, querendo salvar valores arbitrários de um formulário como valores serializados.

Minha resposta evita iterar explicitamente o conteúdo do dicionário: dict(querydict.iterlists())

Para recuperar um valor semelhante a um dicionário que funciona como o original, uma função inversa é usada QueryDict.setlist()para preencher um novo QueryDictvalor. Nesse caso, não acho que a iteração explícita seja evitável.

Minhas funções auxiliares são assim:

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
fonte
3

Atualizar:

myDict = dict(queryDict._iterlists())

Observação: sublinhado _no método iterlists de queryDict. Versão Django: 1.5.1

Parthyz
fonte
3

dict(request.POST) retorna um dicionário python estranho com valores agrupados de matriz.

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

onde como {x:request.POST.get(x) for x in request.POST.keys()}retorna a saída esperada.

{'start': '2017-01-14T21:00', 'stop': '2017-01-14T22:00', 'email': '[email protected]'}
Sandeep
fonte
No Django> = 2.0 (pode funcionar em versões mais antigas também, é apenas a que estou usando), você pode fazer QueryDict.dict()(ou seja request.POST.dict()) e ele retornará os valores corretamente.
Luca Bezerra
2

simplesmente adicione

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

Em sua visualização, os dados serão salvos em querDict como python Dict.

omkar yadav
fonte
1

Foi assim que resolvi esse problema:

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

Como eu, você provavelmente está mais familiarizado com os Dict()métodos em python. No entanto, o QueryDict()também é um objeto fácil de usar. Por exemplo, talvez você queira obter o valor de request.GET QueryDict().

Você pode fazer isso da seguinte forma: request.GET.__getitem__(<key>).

QueryDict()documentação: https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.QueryDict

Marquistador
fonte
1
Evite usar os métodos de sublinhado duplo. A maneira mais pítônica seria usar request.GET.get(<key>)ourequest.GET.getlist(<key>)
Bobort
1

Com, Django 2.2existem algumas soluções limpas:

  1. QueryDict.dict()é mais simples, mas quebrará QueryDictcom listas como valores, por exemplo:
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)

irá produzir

a two  # <--- missed 'one'
b three
  1. dict(QueryDict) é melhor porque fará um dicionário correto de listas:
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)

irá produzir

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

qual é correto.

valex
fonte
0

Experimentei os dois dict(request.POST)e request.POST.dict()percebi que, se você tiver listvalores, por exemplo, 'var1':['value1', 'value2']aninhados em seu request.POST, o último ( request.POST.dict()) apenas me deu acesso ao último item em uma lista aninhada, enquanto o anterior ( dict(request.POST)) me permitiu acessar todos os itens em uma lista aninhada.

Espero que isso ajude alguém.

Codebender
fonte