Question

Je pense que je manque un petit quelque chose ici. Je teste en Python cadre Flask et Flask-MongoAlchemy, et que vous souhaitez convertir une entité en JSON. Voici mon code (Abstraite):

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)

Sans la ligne json.dumps, l'instruction d'impression rapide le bon résultat. Mais seulement si je lance le json.dumps sur le résultat, il donne:

TypeError: ObjectId ( '...') n'est pas JSON sérialisable

Qu'est-ce que je manque?

Était-ce utile?

La solution

Le résultat est un document mongo d'une sorte qui contient le contenu de type ObjectId, que vous aurez à dire JSON comment désérialiser. Vous aurez le même problème avec d'autres types de spécifiques mongo, comme ReferenceField (), EmbeddedDocumentField (), etc. Vous devez écrire une fonction de désérialisation que vous pouvez passer à JSON. Ce que j'utilise est:

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

Ensuite, vous auriez traiter le résultat comme:

return json.dumps(result, default=encode_model)

ou quelque chose à cet effet.

Autres conseils

Vous pouvez également utiliser la méthode query.raw_output() d'avoir ce retour d'instance de requête dictionnaires Python premières au lieu d'un objet Python. Avec un dictionnaire, il devient facile de coder à l'aide JSON json.dumps():

import json
q=db.query(MyObject)
q.raw_output()
json.dumps(q.first())

Référence http://www.mongoalchemy.org /api/expressions/query.html#mongoalchemy.query.Query.raw_output

En combinant les deux réponses précédentes, vous devriez être en mesure de faire quelque chose comme ceci:

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.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top