通过Flask-MongoAlchemy将MongoAlchemy文档编码为JSON

2 投票
3 回答
2621 浏览
提问于 2025-04-17 04:36

我觉得我这里漏掉了什么小东西。我正在测试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)

或者类似的方式。

撰写回答