Irf*_*fan 93 python json mongodb flask
我在使用Python查询文档上的聚合函数后从MongoDB返回的响应,它返回有效的响应,我可以打印它但不能返回它.
错误:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Run Code Online (Sandbox Code Playgroud)
打印:
{'result': [{'_id': ObjectId('51948e86c25f4b1d1c0d303c'), 'api_calls_with_key': 4, 'api_calls_per_day': 0.375, 'api_calls_total': 6, 'api_calls_without_key': 2}], 'ok': 1.0}
Run Code Online (Sandbox Code Playgroud)
但是当我试图返回时:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Run Code Online (Sandbox Code Playgroud)
它是RESTfull调用:
@appv1.route('/v1/analytics')
def get_api_analytics():
# get handle to collections in MongoDB
statistics = sldb.statistics
objectid = ObjectId("51948e86c25f4b1d1c0d303c")
analytics = statistics.aggregate([
{'$match': {'owner': objectid}},
{'$project': {'owner': "$owner",
'api_calls_with_key': {'$cond': [{'$eq': ["$apikey", None]}, 0, 1]},
'api_calls_without_key': {'$cond': [{'$ne': ["$apikey", None]}, 0, 1]}
}},
{'$group': {'_id': "$owner",
'api_calls_with_key': {'$sum': "$api_calls_with_key"},
'api_calls_without_key': {'$sum': "$api_calls_without_key"}
}},
{'$project': {'api_calls_with_key': "$api_calls_with_key",
'api_calls_without_key': "$api_calls_without_key",
'api_calls_total': {'$add': ["$api_calls_with_key", "$api_calls_without_key"]},
'api_calls_per_day': {'$divide': [{'$add': ["$api_calls_with_key", "$api_calls_without_key"]}, {'$dayOfMonth': datetime.now()}]},
}}
])
print(analytics)
return analytics
Run Code Online (Sandbox Code Playgroud)
db连接良好,集合也在那里,我得到了有效的预期结果,但当我尝试返回时,它给了我Json错误.知道如何将响应转换回JOSON.谢谢
tim*_*tim 111
Pymongo提供了json_util - 您可以使用它来代替处理BSON类型
def*_*fuz 99
您应该定义自己JSONEncoder并使用它:
import json
from bson import ObjectId
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
return json.JSONEncoder.default(self, o)
JSONEncoder().encode(analytics)
Run Code Online (Sandbox Code Playgroud)
也可以通过以下方式使用它.
json.encode(analytics, cls=JSONEncoder)
Run Code Online (Sandbox Code Playgroud)
Gar*_*n S 34
>>> from bson import Binary, Code
>>> from bson.json_util import dumps
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary("")}])
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'
Run Code Online (Sandbox Code Playgroud)
来自json_util的实际示例.
与Flask的jsonify不同,"dumps"将返回一个字符串,因此它不能用作Flask的jsonify的1:1替换.
但是这个问题表明我们可以使用json_util.dumps()进行序列化,使用json.loads()转换回dict,最后调用Flask的jsonify.
示例(源自上一个问题的答案):
from bson import json_util, ObjectId
import json
#Lets create some dummy document to prove it will work
page = {'foo': ObjectId(), 'bar': [ObjectId(), ObjectId()]}
#Dump loaded BSON to valid JSON string and reload it as dict
page_sanitized = json.loads(json_util.dumps(page))
return page_sanitized
Run Code Online (Sandbox Code Playgroud)
此解决方案将ObjectId和其他(即二进制,代码等)转换为等效字符串,如"$ oid".
JSON输出如下所示:
{
"_id": {
"$oid": "abc123"
}
}
Run Code Online (Sandbox Code Playgroud)
vin*_*rod 18
from bson import json_util
import json
@app.route('/')
def index():
for _ in "collection_name".find():
return json.dumps(i, indent=4, default=json_util.default)
Run Code Online (Sandbox Code Playgroud)
这是将BSON转换为JSON对象的示例示例.你可以试试这个.
Mos*_*faR 16
作为快速更换,您可以更改{'owner': objectid}为{'owner': str(objectid)}.
但定义自己的JSONEncoder是一个更好的解决方案,这取决于您的要求.
nac*_*son 12
在这里发布,因为我认为它可能对使用Flaskwith 的人有用pymongo。这是我目前允许烧瓶编组 pymongo bson 数据类型的“最佳实践”设置。
mongoflask.py
from datetime import datetime, date
import isodate as iso
from bson import ObjectId
from flask.json import JSONEncoder
from werkzeug.routing import BaseConverter
class MongoJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, (datetime, date)):
return iso.datetime_isoformat(o)
if isinstance(o, ObjectId):
return str(o)
else:
return super().default(o)
class ObjectIdConverter(BaseConverter):
def to_python(self, value):
return ObjectId(value)
def to_url(self, value):
return str(value)
Run Code Online (Sandbox Code Playgroud)
应用程序
from .mongoflask import MongoJSONEncoder, ObjectIdConverter
def create_app():
app = Flask(__name__)
app.json_encoder = MongoJSONEncoder
app.url_map.converters['objectid'] = ObjectIdConverter
# Client sends their string, we interpret it as an ObjectId
@app.route('/users/<objectid:user_id>')
def show_user(user_id):
# setup not shown, pretend this gets us a pymongo db object
db = get_db()
# user_id is a bson.ObjectId ready to use with pymongo!
result = db.users.find_one({'_id': user_id})
# And jsonify returns normal looking json!
# {"_id": "5b6b6959828619572d48a9da",
# "name": "Will",
# "birthday": "1990-03-17T00:00:00Z"}
return jsonify(result)
return app
Run Code Online (Sandbox Code Playgroud)
为什么要这样做而不是为 BSON 或mongod 扩展 JSON提供服务?
我认为为 mongo 提供特殊的 JSON 会给客户端应用程序带来负担。大多数客户端应用程序不会关心以任何复杂的方式使用 mongo 对象。如果我提供扩展的 json,现在我必须在服务器端和客户端使用它。ObjectId并且Timestamp更容易作为字符串使用,这将所有这些 mongo 编组疯狂隔离到服务器。
{
"_id": "5b6b6959828619572d48a9da",
"created_at": "2018-08-08T22:06:17Z"
}
Run Code Online (Sandbox Code Playgroud)
我认为对于大多数应用程序来说,这比使用它更容易。
{
"_id": {"$oid": "5b6b6959828619572d48a9da"},
"created_at": {"$date": 1533837843000}
}
Run Code Online (Sandbox Code Playgroud)
小智 11
对于那些需要使用 Flask 通过 Jsonify 返回数据的人:
cursor = db.collection.find()
data = []
for doc in cursor:
doc['_id'] = str(doc['_id']) # This does the trick!
data.append(doc)
return jsonify(data)
Run Code Online (Sandbox Code Playgroud)
就我而言,我需要这样的东西:
class JsonEncoder():
def encode(self, o):
if '_id' in o:
o['_id'] = str(o['_id'])
return o
Run Code Online (Sandbox Code Playgroud)
收到“无法JSON序列化”错误的大多数用户只需default=str使用即可指定json.dumps。例如:
json.dumps(my_obj, default=str)
Run Code Online (Sandbox Code Playgroud)
这将强制转换为str,从而避免错误。当然,然后查看生成的输出以确认这就是您所需要的。
这就是我最近修复错误的方法
@app.route('/')
def home():
docs = []
for doc in db.person.find():
doc.pop('_id')
docs.append(doc)
return jsonify(docs)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
81123 次 |
| 最近记录: |