51

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?

2
  • cig.parse_qs is deprecated (only retained for backward compatibility), so it may be better to use urlparse.parse_qs Commented Apr 3, 2010 at 11:59
  • Thanks for the tip. I only used it for comparison, so it's not really used. Commented Apr 3, 2010 at 12:03

6 Answers 6

91

The solution (for Python 2) 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.

Sign up to request clarification or add additional context in comments.

5 Comments

If you don't add the [], php will only use criterias=issue, and will ignore the "member"
Also see the answer for this question: stackoverflow.com/questions/6243051/…
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.
Amazing. I was sure this was going to be difficult!
In Python 3 the urllib module has been broken up and the urlencode entry is in the parse submodule. The docs are now at: docs.python.org/3/library/…
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'

3 Comments

Well, it's very easy to write a function that transforms the dict with lists into a list of tuples.
just a note for others, to generate the urlencoded string straight from a regular dict, all you need to do is urllib.urlencode(d.items())
You don't even need to do that, urllib.urlencode(d) should work fine.
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' 

Comments

2

Listcomp of values:

>>> criterias = ['member', 'issue']
>>> urllib.urlencode([('criterias[]', i) for i in criterias])
'criterias%5B%5D=member&criterias%5B%5D=issue'
>>> 

Comments

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]

Comments

0

With Python3, the best way to do this is the following:

from urllib.parse import urlencode

criterias = ['member', 'issue']
print (urlencode(dict(criterias=criterias), doseq=True))

Another method that works is:

print (urlencode([('criterias', criterias)], doseq=True))

Both will produce the following result:

criterias=member&criterias=issue

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.