MongoAlchemy Document Кодировать в JSON через Flask-MongoAlchemy - PullRequest
2 голосов
/ 19 октября 2011

Я думаю, что мне здесь не хватает чего-то маленького. Я тестирую фреймворк 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 оператор print выдает правильный результат. Но только если я запускаю json.dumps для результата, он выдает:

Ошибка типа: ObjectId ('...') не поддерживает сериализацию в формате JSON

Чего мне не хватает?

Ответы [ 3 ]

5 голосов
/ 19 октября 2011

В результате получается документ монго некоторого вида, который содержит контент типа ObjectId, который вам нужно будет рассказать json, как десериализовать. У вас будет такая же проблема с другими монго-специфическими типами, такими как 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)

или что-то на этот счет.

1 голос
/ 02 сентября 2015

Вы также можете использовать метод query.raw_output(), чтобы этот экземпляр запроса возвращал необработанные словари Python вместо объекта Python. Со словарем становится легко кодировать в JSON, используя json.dumps():

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

0 голосов
/ 29 октября 2016

Объединив два предыдущих ответа, вы сможете сделать что-то вроде этого:

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...