Search code examples
pythonflaskpython-requestsflask-restful

Only first key is available after "put"


I try to implement put handler for my resource. Here's the code:

class Settings(restful.Resource):
    def put(self):
        settings = request.form['settings']
        print settings

Here's how I put data there:

import requests
url='http://localhost:8000/settings'
data = {'settings': {
            'record': {
                'b': 'ok',
                'c': 20,
                'd': 60,
            },
            'b': {
                'c': {
                    'd': 3,
                    'e': 2,
                    'f': 2,
                },
                'd': 5,
                'a': 'voice',
                'k': {
                    'l': 11.0,
                    'm': 23.0,
                },
            }
        }
}
requests.put(url, data)

And there's only record printed out in my console when I do that so when I do validation, it fails because the data is not dictionary. I can't figure out what's wrong.

It looks the same as code in Flask-RESTful Quickstart, and if I get it right requests works with dictionaries.


Solution

  • When you pass in a dictionary as the data argument, requests encodes the data to ``application/x-www-form-urlencoded`, just like a browser form would. This encoding format does not support structured data beyond an (ordered, non-unique) key-value sequence.

    Don't use application/x-www-form-urlencoded to post structured data. Use JSON instead:

    import json
    
    # ...
    
    requests.put(url, json.dumps(data), headers={'Content-Type': 'application/json'})
    

    Then in Flask use request.get_json() to load the payload again:

    class Settings(restful.Resource):
        def put(self):
            settings = request.get_json()['settings']
            print settings
    

    If you are using requests version 2.4.2 or newer, you can also leave the JSON encoding to the requests library; simply pass in the data object in as the json keyword argument; the correct Content-Type header will be set too:

    requests.put(url, json=data)
    

    Note that you then don't have to call json.dumps() yourself.