【问题标题】:Python Flask JSON in wrong order: post and get functionsPython Flask JSON 顺序错误:发布和获取函数
【发布时间】:2020-02-28 01:14:08
【问题描述】:

我的 Flask 服务器的 post 和 get 函数如下所示:

from flask import Flask, request
import json
app = Flask(__name__)

tasks=[]

#Create a new task
@app.route('/v1/tasks', methods=['POST'])
def post():
    data=request.get_json()
    if "title" not in data:
        return bulkadd(data)
    title=data["title"]
    tasks.append(json.dumps({"id": len(tasks)+1, "title": title, "is_completed": "false"}))
    index=len(tasks)
    return json.dumps({"id": index}), 201

#List all tasks created
@app.route('/v1/tasks', methods=['GET'])
def getall():
   app.logger.info({"tasks": tasks})
   return json.dumps({"tasks": tasks})

两次调用 post 后,get 的输出如下:

{"tasks": ["{\"is_completed\": \"false\", \"id\": 1, \"title\":\"Test Task 2\"}", "{\"is_completed\": \"false\", \"id\": 2, \"t:03] "POST /v1/tasks HTTP/1.1" 201 -itle\": \"Test Task 2\"}"]}

相反,这就是我想要的输出格式:

{
   tasks: [
     {id: 1, title: "Test Task 1", is_completed: true},
     {id: 2, title: "Test Task 2", is_completed: false}
   ]
}

为什么顺序不同,“\”是什么意思?

感谢您的帮助!

编辑 1: 你能帮我解释一下为什么下面的 post 函数测试会抛出这个错误吗?:

这不会生成有效的 json 吗?

return json.dumps({"id": index}), 201

_____________________________________ test_create_task _____________________________________
    def test_create_task():
        r = requests.post('http://localhost:5000/v1/tasks', json={"title": "My First Task"})>       assert isinstance(r.json()["id"], int)

project1-test3.py:6:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/alexanderfarr/.local/lib/python3.6/site-packages/requests/models.py:898: in json      
    return complexjson.loads(self.text, **kwargs)
/usr/lib/python3/dist-packages/simplejson/__init__.py:518: in loads
    return _default_decoder.decode(s)
/usr/lib/python3/dist-packages/simplejson/decoder.py:370: in decode
    obj, end = self.raw_decode(s)

【问题讨论】:

  • 您的示例输出不是有效的 JSON。
  • @KlausD。如何更改我的代码以创建有效的 JSON?
  • @KlausD。它有效的JSON,只是内部项目是双重编码的。我的回答提供了完整的解释。
  • @metatoaster 我一直在谈论他想要的输出与未引用的键。
  • @KlausD。哦,我在实际发布的内容上一定没有滚动足够远,但我的评估基于代码应该产生的输出,而不是实际粘贴到问题中的内容(与控制台输出混合,有时复制/粘贴会导致奇怪)。

标签: python json python-3.x flask


【解决方案1】:

tasks 列表中的输出具有 \" 的原因是因为各个元素实际上是一个字符串,并且鉴于 JSON 使用 " 字符来引用字符串,其中的文字 "必须通过在其前面加上转义字符 \ 来对其进行转义,从而使 \"。由于您显然不想要字符串而是实际对象,因此您只需要在将该对象添加到列表之前不将该对象编码为字符串。

所以不是

def post():
    ...
    tasks.append(json.dumps({"id": len(tasks)+1, "title": title, "is_completed": "false"}))

简单的做

    tasks.append({"id": len(tasks)+1, "title": title, "is_completed": "false"})

现在,如果您想以特定(非字母)方式为键指定特定的输出顺序,this SO thread 将详细介绍其背后的细节。简而言之,您可能希望为 post 函数执行此操作:

import json
from collections import OrderedDict
from flask import Flask, request

app = Flask(__name__)
tasks = []

# Create a new task
@app.route('/v1/tasks', methods=['POST'])
def post():
    data = request.get_json()
    if "title" not in data:
        return bulkadd(data)
    title = data["title"]
    tasks.append(OrderedDict((
        ('id', len(tasks) + 1),
        ('title', title),
        ('is_completed', False),
    )))
    index = len(tasks)
    return json.dumps({"id": index}), 201


# List all tasks created
@app.route('/v1/tasks', methods=['GET'])
def getall():
   app.logger.info({"tasks": tasks})
   return json.dumps({"tasks": tasks}, indent=4)

示例运行:

$ curl http://127.0.0.1:5000/v1/tasks --data '{"title": "hi"}' -H 'Content-Type: application/json'
{"id": 1}
$ curl http://127.0.0.1:5000/v1/tasks
{
    "tasks": [
        {
            "id": 1,
            "title": "hi",
            "is_completed": false
        }
    ]
}

替代方案,使用requests(使用支持json 关键字参数的最新版本):

>>> import requests
>>> r = requests.post('http://localhost:5000/v1/tasks', json={"title": "My First Task"})
>>> r.json()["id"]
1
>>> print(requests.get('http://localhost:5000/v1/tasks').text)
{
    "tasks": [
        {
            "id": 1,
            "title": "My First Task",
            "is_completed": false
        }
    ]
}

您可能要考虑不为is_completed 引用false(我在这里做了),因为这会将值转换为字符串,而不是您可能打算传达的布尔值。另请注意,对于此端点的GET 版本,我为json.dumps 添加了indent=4 参数,以便完成漂亮的格式化,但请注意,这会增加有效负载的大小。

【讨论】:

  • 谢谢@metatoaster!你能帮我做新的编辑吗?谢谢!
  • 请参阅此thread,了解为什么这可能不起作用,但简而言之,您至少需要requests>=2.4.2 才能使用json 参数。我无法使用适当版本的 requests 重现您的问题。
  • 我很确定我有请求>=2.4.2 因为我可以将 JSON 作为参数传递。我如何验证这一点?
  • 一种方法是使用调试器单步执行代码并验证传递的所有值是否符合您的预期。既然你问了一个不同的问题,看起来这不是你的实际问题,而且还有其他东西隐藏了它。在任何情况下,答案都会被编辑以包含一个带有请求的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
相关资源
最近更新 更多