54

Imagine that I have a dictionary in my Django application:

dict = {'a': 'one', 'b': 'two', }

Now I want to easily create an urlencoded list of GET parameters from this dictionary. Of course I could loop through the dictionary, urlencode keys and values and then concatenate the string by myself, but there must be an easier way. I would like to use a QueryDict instance. QueryDict is a subclass of dict, so it should be possible somehow.

qdict = QueryDict(dict) # this does not actually work
print qdict.urlencode()

How would I make the second to last line work?

winsmith
  • 20,791
  • 9
  • 39
  • 49

5 Answers5

90

How about?

from django.http import QueryDict

ordinary_dict = {'a': 'one', 'b': 'two', }
query_dict = QueryDict('', mutable=True)
query_dict.update(ordinary_dict)
valex
  • 5,163
  • 2
  • 33
  • 40
miki725
  • 27,207
  • 17
  • 105
  • 121
24

Python has a built in tool for encoding a dictionary (any mapping object) into a query string

params = {'a': 'one', 'b': 'two', }

urllib.urlencode(params)

'a=one&b=two'

http://docs.python.org/2/library/urllib.html#urllib.urlencode

QueryDict takes a querystring as first param of its contstructor

def __init__(self, query_string, mutable=False, encoding=None):

q = QueryDict('a=1&b=2')

https://github.com/django/django/blob/master/django/http/request.py#L260

Update: in Python3, urlencode has moved to urllib.parse:

from urllib.parse import urlencode

params = {'a': 'one', 'b': 'two', }
urlencode(params)
'a=one&b=two'
Mathieu Dhondt
  • 8,405
  • 5
  • 37
  • 58
dm03514
  • 54,664
  • 18
  • 108
  • 145
16

Actually a little indirect but more logical way to achieve this is using MultiValueDict. This way multiple values per key can be stored in a QueryDict and .getlist method should then work fine.

from django.http.request import QueryDict, MultiValueDict
dictionary = {'my_age': ['23'], 'my_girlfriend_age': ['25', '27'], }

qdict = QueryDict('', mutable=True)
qdict.update(MultiValueDict(dictionary))

print qdict.get('my_age')  # 23
print qdict['my_girlfriend_age']  # 27
print qdict.getlist('my_girlfriend_age')  # ['25', '27']
Koterpillar
  • 7,883
  • 2
  • 25
  • 41
Arpit Singh
  • 3,387
  • 2
  • 17
  • 11
  • 2
    Hm.. Unlike the others, which only handle single values, this one requires value to be lists (it breaks strings into a list of characters). Seems there's no simple way to handle both. – Izkata Jun 18 '18 at 18:05
5

My solution works both for single and multiple key values:

def dict_to_querydict(dictionary):
    from django.http import QueryDict
    from django.utils.datastructures import MultiValueDict

    qdict = QueryDict('', mutable=True)

    for key, value in dictionary.items():
        d = {key: value}
        qdict.update(MultiValueDict(d) if isinstance(value, list) else d)

    return qdict
Erik Telepovský
  • 523
  • 7
  • 11
0

I couldn't be much more late to the party, but I recently needed to do the same - but to preserve the read-only behaviour of a 'real' QueryDict from a response object.

Adapting the code from QueryDict.fromkeys() method gave a nice function:

from django.http import QueryDict

def querydict_from_dict(data: Dict[str, Any],  mutable=False) -> QueryDict:
    """
    Return a new QueryDict with keys (may be repeated) from an iterable and
    values from value.
    """
    q = QueryDict('', mutable=True)

    for key in data:
        q.appendlist(key, data[key])

    if not mutable:
        q._mutable = False

    return q