Python Flask-Restful POST не принимает аргументы JSON

Я очень новичок в Flask (& Flask-Restful).

Моя проблема: аргументы json для POST получают значение NONE (не работает).

Я могу принимать аргументы из form-data, используя плагин POSTMAN для хром. Но, когда я переключаюсь на raw (& feed a json), он не может прочитать json и присваивает NONE всем моим аргументам.

Я прочитал некоторые связанные сообщения о stackoverflow, связанные с этим: link1, link2, link3... ничто из этого не помогло мне.

Я использую python-2.6, Flask-Restful-0.3.3, Flask-0.10.1, Chrome, POSTMAN в Oracle Linux 6.5.

Код Python app.py:

from flask import Flask, jsonify
from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('username', type=str)
parser.add_argument('password', type=str)

class HelloWorld(Resource):
    def post(self):
        args = parser.parse_args()
        un = str(args['username'])
        pw = str(args['password'])
        return jsonify(u=un, p=pw)

api.add_resource(HelloWorld, '/testing')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5444 ,debug=True)

Тестирование этого с помощью POSTMAN:

  • Использование form-data: работает отлично!
  • Использование rawjson: вызывает эту проблему

Проверенные вещи # 1:

Добавьте параметр json в мой метод add_argument() в app.py

parser = reqparse.RequestParser()
parser.add_argument('username', type=str, location='json') # added json
parser.add_argument('password', type=str, location='json') # added json

Input: { "username": "hello", "password": "world" }

Output: { "p": "None", "u": "None" }

Проверенные вещи # 2:

Измените тип на unicode в add_argument() в app.py

parser = reqparse.RequestParser()
parser.add_argument('username', type=unicode, location='json') # change type to unicode
parser.add_argument('password', type=unicode, location='json') # change type to unicode

Input: { "username": "hello", "password": "world" }

Output: { "p": "None", "u": "None" }


PS: Я буду постоянно обновлять свой вопрос с каждой неудачной попыткой. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация, чтобы сделать этот вопрос более понятным.

Ответ 1

В соответствии с документацией для Request.json и новой Request.get_json, у вас должен быть тип mimetype в вашем запросе POST, установленном на application/json. Это единственный способ, с помощью которого флажок автоматически анализирует ваши данные JSON в свойстве Request.json, который, как мне кажется, зависит от того, что Flask-Restful зависит от получения данных JSON.

ПРИМЕЧАНИЕ. Более новая функция get_json имеет возможность принудительно анализировать данные POST как JSON независимо от типа mimetype

Ответ 2

Ответ на junnytony дал мне подсказку, и я продолжил этот подход. get_json похоже, сделал трюк.
from flask import Flask, jsonify, request
from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)
api = Api(app)

#parser = reqparse.RequestParser()
#parser.add_argument('username', type=unicode, location='json')
#parser.add_argument('password', type=unicode, location='json')

class HelloWorld(Resource):
    def post(self):
        json_data = request.get_json(force=True)
        un = json_data['username']
        pw = json_data['password']
        #args = parser.parse_args()
        #un = str(args['username'])
        #pw = str(args['password'])
        return jsonify(u=un, p=pw)

api.add_resource(HelloWorld, '/testing')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5444 ,debug=True)

Ответ 3

Я столкнулся с подобной проблемой, и вот решение, которое работает для меня. скажем, ваше приложение выглядит так:

from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse

app = Flask(__name__)
api = Api(app)

# Define parser and request args
parser = reqparse.RequestParser()
parser.add_argument('last_name', type=str)
parser.add_argument('first_name', type=str)
# not the type=dict
parser.add_argument('personal_data', type=dict)


class Item(Resource):

    def post(self):

        args = parser.parse_args()

        ln = args['last_name']
        fn = args['first_name']
        # we can also easily parse nested structures
        age = args['personal_data']['age']
        nn = args['personal_data']['nicknames']

        return jsonify(fn=fn, ln=ln, age=age, nn=nn)


api.add_resource(Item, '/item')

if __name__ == '__main__':
    app.run(debug=True)

Теперь вы можете легко создать некоторые данные JSON:

import json

d = {'last_name': 'smith', 'first_name': 'john', 'personal_data': {'age': 18, 'height': 180, 'nicknames': ['johnny', 'grandmaster']}}

print(json.dumps(d, indent=4))

{
    "last_name": "smith",
    "first_name": "john",
    "personal_data": {
        "age": 18,
        "height": 180,
        "nicknames": [
            "johnny",
            "grandmaster"
        ]
    }
}

json.dumps(d)
'{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'

и позвоните в приложение:

curl http://localhost:5000/item -d '{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'

Это завершится с ошибкой (я сократил трассировку):

age = args ['personal_data'] ['age']
TypeError: объект 'NoneType' не может быть подписан

причина в том, что заголовок не указан. Если мы добавим

-H "Content-Type: application/json"

а затем позвоните

curl http://localhost:5000/item -H "Content-Type: application/json" -d '{"last_name": "smith", "first_name": "john", "personal_data": {"age": 18, "height": 180, "nicknames": ["johnny", "grandmaster"]}}'

Вывод выглядит как и ожидалось:

{
  "age": 18, 
  "fn": "john", 
  "ln": "smith", 
  "nn": [
    "johnny", 
    "grandmaster"
  ]
}

Эта функция также может быть дополнительно упрощена до:

class Item(Resource):

    def post(self):

        json_data = request.get_json()
        # create your response below

как показано выше.

Ответ 4

После форсирования запроса на разбор json он сработал у меня. Вот код:

from flask import Flask, jsonify, request
from flask_restful import reqparse, abort, Api, Resource

app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('username', type=str)
parser.add_argument('password', type=str)

class HelloWorld(Resource):
    def post(self):
        request.get_json(force=True)
        args = parser.parse_args()
        un = str(args['username'])
        pw = str(args['password'])
        return jsonify(u=un, p=pw)

api.add_resource(HelloWorld, '/testing')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5444 ,debug=True)