Frage

Ich glaube, ich vermisse hier etwas Kleines. Ich teste Python Framework Flask und Flask-Mongoalchemy aus und möchte ein Entität in JSON-Ausgabe umwandeln. Hier ist mein Code (abstrahiert):

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)

Ohne die Zeile json.dumps fordert die Druckanweisung das richtige Ergebnis auf. Aber nur, wenn ich die json.dumps zum Ergebnis leite, ergibt es:

TypeError: ObjectID ('...') ist nicht json serialisierbar

Was vermisse ich?

War es hilfreich?

Lösung

Das Ergebnis ist ein Mongo-Dokument, das Inhalte vom ObjektID-Typ enthält, das JSON mitgeteilt werden muss, wie man sich deserialisieren kann. Sie haben das gleiche Problem mit anderen mongospezifischen Typen wie Referencefield (), EmbeddedDocumentField () usw. Sie müssen eine Deserialisierungsfunktion schreiben, die Sie an JSON übergeben können. Was ich benutze ist:

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

Dann würden Sie das Ergebnis verarbeiten als:

return json.dumps(result, default=encode_model)

oder etwas in diesem Effekt.

Andere Tipps

Sie können auch die verwenden query.raw_output() Methode, um diese Abfrageinstanz zu haben, geben Sie rohe Python -Wörterbücher anstelle eines Python -Objekts zurück. Mit einem Wörterbuch kann es leicht zu JSON zu kodieren, wenn es verwendet wird json.dumps():

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

Bezug http://www.mongoalchemy.org/api/expressions/query.html#mongoalchemy.query.query.raw_output

Wenn Sie die beiden vorherigen Antworten kombinieren, sollten Sie in der Lage sein, so etwas zu tun:

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.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top