Search code examples
pythonpython-3.xurlencode

Encode URL with nested dictionaries


I am using an API that doesn't accept JSON in the requests' bodies. It uses x-www-form-urlencoded.

Thus, if I have to send this dict:

{
    'a': 1,
    'b': 2,
    'c': {
        'k': 3,
        'v': 4,
        'l': {
            'p': 5,
            'q': 6,
        },
    },
}

It have to be encoded like this:

a=1
b=2
c[k]=3
c[v]=4
c[l][p]=5
c[l][q]=6

However, urllib.parse.urlencode won't parse the dict this way. Instead it's going to encode c content literally and put within it (c={encodeddict}).

I tried to implement some encoder like this by myself, but I couldn't get to deal with multiple nested dicts. I only managed to encode 1-level dicts (like c[k]=3), but not recursively to the last level (c[l][p]=5, for example).

What is the best way to achieve this kind of encoding in Python 3?


Solution

  • Using recursion:

    pass your dict to dict_to_urlencoded(), and it'll return encoded format string based on your description. (unsorted)

    def dict_to_urlencoded(d):
        return kv_translation(d, "", "")
    
    
    def kv_translation(d, line, final_str):
        for key, value in d.items():
            key_str = key if not line else "[{}]".format(key)
            if type(value) is dict:
                final_str = kv_translation(d[key], line + key_str, final_str)
            elif type(value) is list:
                key_str += '[]'
            elif type(value) is not str:
                value = str(value)
            else:
                final_str = "{}{}{}={}\n".format(final_str, line, key_str, urlencode(value))
    
    return final_str