MongoDB ReferenceField для JSON
Я пишу API с Flask. Я использую ReferenceField для пользователя, который написал сообщение. API должен возвращать объект JSON с данными о публикации и данными о пользователе.
Конечная точка колбы:
@app.route("/api/posts")
def posts_index():
posts = Post.objects()
return jsonify({
"posts": json.loads(posts.to_json())
})
Модель базы данных:
class User(Document):
email = EmailField(required=True, unique=True)
username = StringField(max_length=50, required=True, unique=True)
password = StringField(required=True)
created = DateTimeField(required=True, default=datetime.datetime.now())
class Comment(EmbeddedDocument):
content = StringField(max_length=5000)
user = ReferenceField(User)
created = DateTimeField(required=True, default=datetime.datetime.now())
class Post(Document):
title = StringField(max_length=120, required=True)
user = ReferenceField(User, reverse_delete_rule=CASCADE)
content = StringField(max_length=5000)
comments = ListField(EmbeddedDocumentField(Comment))
created = DateTimeField(required=True, default=datetime.datetime.now())
JSON ответ:
{
"posts": [
{
"_id": {
"$oid": "5a5efd1f9ef3161fc64cb95a"
},
"comments": [],
"content": "Lorem Ipsum",
"created": {
"$date": 1516178223018
},
"title": "Hello",
"user": {
"$oid": "5a5d0b9b9ef316220b6d9881"
}
},
{
"_id": {
"$oid": "5a5efd1f9ef3161fc64cb95b"
},
"comments": [],
"content": "Lorem Ipsum Dolor",
"created": {
"$date": 1516178223018
},
"title": "Hello Again",
"user": {
"$oid": "5a5d0b9b9ef316220b6d9881"
}
}
]
}
Я хотел бы получить ответ json, но ReferenceField должен содержать информацию о пользователе.
1 ответ
Hasattr не работает в примере с именем атрибута $oid:
value = {'$oid': '5e8764ed70f190b802bdc008'}
if hasattr(value, '$oid'):
print('this never prints')
Мне пришлось получить к нему доступ таким образом:
try:
oid = value['$oid']
print('this works')
except:
print('no oid')
Во-первых, вы должны рекурсивно перебирать все поля и пытаться получить его значение. Я написал небольшую функцию, которая делает это.
from mongoengine import Document, EmbeddedDocument
from mongoengine.queryset import QuerySet
def to_dict(obj):
if isinstance(obj, (QuerySet, list)):
return map(to_dict, obj)
elif isinstance(obj, (Document, EmbeddedDocument)):
doc = {}
for field_name, field_type in obj._fields.iteritems():
field_value = getattr(obj, field_name)
doc[field_name] = to_dict(field_value)
return doc
else:
return obj
Назовите эту функцию как to_dict(Posts.objects)
или же to_dict(Post.objects.first())
и вы должны получить глубокий словарь.
Затем создайте ответ json с помощью пользовательского кодировщика json.
import json, bson
def json_response(obj, cls=None):
response = make_response(json.dumps(obj, cls=cls))
response.content_type = 'application/json'
return response
class MongoJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, bson.ObjectId):
return str(obj)
if isinstance(obj, bson.DBRef):
return str(obj.id)
return json.JSONEncoder.default(self, obj)
@app.route('/')
def index():
posts_json = to_dict(Post.objects)
return json_response(dict(data=posts_json), cls=MongoJsonEncoder)