Mongoalchemie-Dokument für JSON über Flask-Mongoalchemie
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?
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.