50

I'm trying to urlencode an dictionary in python with urllib.urlencode. The problem is, I have to encode an array.

The result needs to be:

criterias%5B%5D=member&criterias%5B%5D=issue
#unquoted: criterias[]=member&criterias[]=issue

But the result I get is:

criterias=%5B%27member%27%2C+%27issue%27%5D
#unquoted: criterias=['member',+'issue']

I have tried several things, but I can't seem to get the right result.

import urllib
criterias = ['member', 'issue']
params = {
    'criterias[]': criterias,
}
print urllib.urlencode(params)

If I use cgi.parse_qs to decode a correct query string, I get this as result:

{'criterias[]': ['member', 'issue']}

But if I encode that result, I get a wrong result back. Is there a way to produce the expected result?

Ikke
  • 99,403
  • 23
  • 97
  • 120

5 Answers5

89

The solution is far simpler than the ones listed above.

>>> import urllib
>>> params = {'criterias[]': ['member', 'issue']}
>>> 
>>> print urllib.urlencode(params, True)
criterias%5B%5D=member&criterias%5B%5D=issue

Note the True. See http://docs.python.org/library/urllib.html#urllib.urlencode the doseq variable.

As a side note, you do not need the [] for it to work as an array (which is why urllib does not include it). This means that you do not not need to add the [] to all your array keys.

CSTobey
  • 1,491
  • 13
  • 9
  • 1
    If you don't add the [], php will only use criterias=issue, and will ignore the "member" – Martin Gerhardy Nov 18 '15 at 15:12
  • Also see the answer for this question: http://stackoverflow.com/questions/6243051/how-to-pass-an-array-within-a-query-string – Martin Gerhardy Nov 18 '15 at 15:24
  • 2
    To clarify, Python doesn't care if the `[]`'s are there: it will convert it correctly regardless. But yes, PHP (and maybe other languages?) does care, so if you have an external dependency on such systems, it is best to leave the `[]`'s... it just looks weird in Python. – CSTobey Dec 16 '15 at 15:46
  • Amazing. I was *sure* this was going to be difficult! – Tom Russell May 10 '17 at 21:09
  • 1
    In Python 3 the `urllib` module has been broken up and the `urlencode` entry is in the `parse` submodule. The docs are now at: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode – brotskydotcom May 25 '20 at 05:24
12

You can use a list of key-value pairs (tuples):

>>> urllib.urlencode([('criterias[]', 'member'), ('criterias[]', 'issue')])
'criterias%5B%5D=member&criterias%5B%5D=issue'
Lukáš Lalinský
  • 40,587
  • 6
  • 104
  • 126
3

To abstract this out to work for any parameter dictionary and convert it into a list of tuples:

import urllib

def url_encode_params(params={}):
    if not isinstance(params, dict): 
        raise Exception("You must pass in a dictionary!")
    params_list = []
    for k,v in params.items():
        if isinstance(v, list): params_list.extend([(k, x) for x in v])
        else: params_list.append((k, v))
    return urllib.urlencode(params_list)

Which should now work for both the above example as well as a dictionary with some strings and some arrays as values:

criterias = ['member', 'issue']
params = {
    'criterias[]': criterias,
}
url_encode_params(params)
>>'criterias%5B%5D=member&criterias%5B%5D=issue' 
David
  • 671
  • 5
  • 10
2

Listcomp of values:

>>> criterias = ['member', 'issue']
>>> urllib.urlencode([('criterias[]', i) for i in criterias])
'criterias%5B%5D=member&criterias%5B%5D=issue'
>>> 
gimel
  • 83,368
  • 10
  • 76
  • 104
1

as aws api defines its get url: params.0=foo&params.1=bar

however, the disadvantage is that you need to write code to encode and decode by your own, the result is: params=[foo, bar]

ZhiQiang Fan
  • 986
  • 6
  • 7