通过Flask-MongoAlchemy将MongoAlchemy文档编码为JSON
我觉得我这里漏掉了什么小东西。我正在测试Python的Flask框架和Flask-MongoAlchemy,想把一个实体转换成JSON格式的输出。以下是我的代码(简化版):
from flask import Flask
from flaskext.mongoalchemy import MongoAlchemy
try:
from bson.objectid import ObjectId
except:
pass
#a bunch of code to open the mongoDB
class ClassA(db.Document):
title = db.StringField()
field1 = db.StringField()
field2 = db.BoolField()
@app.route('/api/classA', methods=['GET'])
def api_list_all
a = ClassA.query.all()
result = []
for b in a:
result.append(b.wrap())
print result
return json.dumps(result)
如果没有json.dumps这一行,打印出来的结果是正确的。但是一旦我对结果使用json.dumps,就会出现:
类型错误:ObjectId('...') 不能被转换成JSON格式
我漏掉了什么呢?
3 个回答
0
结合之前的两个回答,你应该可以这样做:
from bson import json_util
# ...
@app.route('/api/classA', methods=['GET'])
def api_list_all
a = ClassA.query.all()
result = []
for b in a:
result.append(b.wrap())
print result
return json_utils.dumps(result) # Change here.
1
你还可以使用 query.raw_output()
这个方法,让查询的结果返回原始的 Python 字典,而不是 Python 对象。使用字典的话,就可以很方便地通过 json.dumps()
转换成 JSON 格式了:
import json
q=db.query(MyObject)
q.raw_output()
json.dumps(q.first())
参考链接 http://www.mongoalchemy.org/api/expressions/query.html#mongoalchemy.query.Query.raw_output
5
结果是一个MongoDB文档,里面包含了ObjectId类型的内容。你需要告诉json怎么把这些内容转换成可以使用的格式。对于其他MongoDB特有的类型,比如ReferenceField()、EmbeddedDocumentField()等,你也会遇到同样的问题。
你需要写一个反序列化的函数,这样就可以把数据传给json。我用的是:
def encode_model(obj, recursive=False):
if obj is None:
return obj
if isinstance(obj, (mongoengine.Document, mongoengine.EmbeddedDocument)):
out = dict(obj._data)
for k,v in out.items():
if isinstance(v, ObjectId):
if k is None:
out['_id'] = str(v)
del(out[k])
else:
# Unlikely that we'll hit this since ObjectId is always NULL key
out[k] = str(v)
else:
out[k] = encode_model(v)
elif isinstance(obj, mongoengine.queryset.QuerySet):
out = encode_model(list(obj))
elif isinstance(obj, ModuleType):
out = None
elif isinstance(obj, groupby):
out = [ (g,list(l)) for g,l in obj ]
elif isinstance(obj, (list)):
out = [encode_model(item) for item in obj]
elif isinstance(obj, (dict)):
out = dict([(k,encode_model(v)) for (k,v) in obj.items()])
elif isinstance(obj, datetime.datetime):
out = str(obj)
elif isinstance(obj, ObjectId):
out = {'ObjectId':str(obj)}
elif isinstance(obj, (str, unicode)):
out = obj
elif isinstance(obj, float):
out = str(obj)
else:
raise TypeError, "Could not JSON-encode type '%s': %s" % (type(obj), str(obj))
return out
然后你可以这样处理结果:
return json.dumps(result, default=encode_model)
或者类似的方式。