对 Python 返回 JSON 作为字符串而不是文字感到困惑
Posted
技术标签:
【中文标题】对 Python 返回 JSON 作为字符串而不是文字感到困惑【英文标题】:Confused by Python returning JSON as string instead of literal 【发布时间】:2013-11-12 02:35:29 【问题描述】:我在 RoR 和 Rails 中完成了一些编码,当我通过 API 调用返回 JSON 对象时,它返回为
"id" : "1", "name" : "Dan"
。
但是在 Python(使用 Flask 和 Flask-SQLAlchemy)中,当我通过 json.dumps 或 jsonpickle.encode 返回 JSON 对象时,它会返回为
" \"id\" : \"1\", \"name\": \"Dan\" "
看起来非常笨拙,因为它在另一端不容易被解析(在这种情况下由 ios 应用程序 - Obj-C)。
我在这里遗漏了什么,我应该怎么做才能将它作为 JSON 文字而不是 JSON 字符串返回?
这是我的代码的样子:
people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)
json_object = jsonpickle.encode(friends.first().as_dict(), unpicklable=False, keys=True)
print(json_object) # this prints here, i.e. "id" : "1", "name" : "Dan"
return json_object # this returns " \"id\" : \"1\", \"name\": \"Dan\" " to the browser
【问题讨论】:
json.dumps 将返回对象的字符串表示形式。请参阅帮助(json.dumps)-> 将obj
序列化为 JSON 格式的 str
。
如果你想要JSON,你应该使用相关模块序列化为JSON。打印一些东西不会把它变成 JSON。
一个 JSON 文字 is 一个字符串。 JSON 是一种表示法。 JSON 只能是一个字符序列。您将数据结构与其表示混淆了。
你显示的代码不可能做你声称的事情。 json_object = print(json_object)
会将 json_object
设置为 None
。
是的,你是对的。我写代码太快了!对不起。我在上面编辑过。问题是当我将它返回到浏览器时,而不是当我打印它时。
【参考方案1】:
您的理解中缺少的是,当您在 Python 中使用 JSON 模块时,您不是在使用 JSON 对象。 JSON 根据定义只是一个符合特定标准的字符串。
假设你有字符串:
friends = '"name": "Fred", "id": 1'
如果你想在 python 中处理这些数据,你需要将它加载到一个 python 对象中:
import json
friends_obj = json.loads(friends)
此时friends_obj是一个python字典。
如果你想转换它(或任何其他 python 字典或列表),那么这就是 json.dumps 派上用场的地方:
friends_str = json.dumps(friends_obj)
print friends_str
'"name": "Fred", "id": 1'
但是,如果我们尝试“转储”原始朋友字符串,您会看到不同的结果:
dumped_str = json.dumps(friends)
print dumped_str
'"\\"name\\": \\"Fred\\", \\"id\\": 1"'
这是因为您基本上是在尝试将普通字符串编码为 JSON,并且它正在转义字符。我希望这有助于理解事情!
干杯
【讨论】:
谢谢,问题不在于打印。打印时没问题,当我将它返回给浏览器时,它是双重编码的。即return json_object # this returns " \"id\" : \"1\", \"name\": \"Dan\" "
到浏览器【参考方案2】:
看起来您在这里使用 Django,在这种情况下,请执行类似的操作
from django.utils import simplejson as json
...
return HttpResponse(json.dumps(friends.first().as_dict()))
【讨论】:
我没有使用Django,所以我想我不能使用HttpResponse?我正在使用 Python、Flask、Flask-SQLAlchemy.. 啊,对不起,我草率下结论;一些语法看起来像 Django 但不是。 Django 是模块化的,因此您可以根据需要使用一些部分,但如果您使用的是 Flask,则可能不需要。【参考方案3】:这几乎总是表明您在某处对数据进行了双重编码。例如:
>>> obj = "id" : "1", "name" : "Dan"
>>> j = json.dumps(obj)
>>> jj = json.dumps(j)
>>> print(obj)
'id': '1', 'name': 'Dan'
>>> print(j)
"id": "1", "name": "Dan"
>>> print(jj)
"\"id\": \"1\", \"name\": \"Dan\""
这里,jj
是一个完全有效的 JSON 字符串表示形式——但它不是 obj
的表示形式,它是字符串 j
的表示形式,这是没有用的。
通常你不会直接这样做;相反,要么你从一个 JSON 字符串而不是一个对象开始(例如,你从客户端请求或文本文件中获取它),要么你调用了库中的某个函数,如 requests
或 jsonpickle
使用已编码的字符串隐式调用json.dumps
。但无论哪种方式,都是同一个问题,但解决方案相同:只是不要双重编码。
【讨论】:
我在 Flask-SQLAlchemy 行上使用 jsonpickle.encode,该行已转换为 dict(即jsonpickle.encode(friends.first().as_dict(), unpicklable=False, keys=True)
),因此除非我误解了某些内容,否则它可能还不是编码字符串。
@Dan:你从什么地方退回来的?您的应用程序是如何配置的?如果 Flask 期望你给它一个它将编码的对象,而你正在编码一个对象并给它结果字符串,它最终会被双重编码。
@Dan:顺便说一句,你为什么使用jsonpickle
而不是stdlib json
模块,或者Flask 的内置jsonify
? jsonpickle
的全部意义在于,它为您提供了一种包装和解包不直接映射到 JSON 的 Python 类型(如自定义类)的方法,除非对方也使用 jsonpickle
,否则这是无用的,这是网络浏览器或 ObjC 应用显然不是。
你是对的。那是我的问题:/我应该一直在使用 jsonify。【参考方案4】:
您应该使用flask.jsonify
,它不仅会正确编码,还会相应地设置content-type
标头。
people = models.UserRelationships.query.filter_by(user_id=user_id, active=ACTIVE_RECORD)
friends = people.filter_by(friends=YES)
return jsonify(friends.first().as_dict())
【讨论】:
谢谢!我的问题是无法理解 http 响应和 JSON 字符串之间的区别。将它用于 API 时,我正在关注 http 响应。以上是关于对 Python 返回 JSON 作为字符串而不是文字感到困惑的主要内容,如果未能解决你的问题,请参考以下文章