如何在mongoengine中获取ReferenceField数据?
我遇到了一个问题,我在获取json格式的数据时,只能拿到oid
,我想要获取下面这个用户集合的实际用户名:
class User(db.Document):
username = db.StringField(required=True)
password_hash = db.StringField()
is_admin = db.IntField(default=0)
class Message(db.EmbeddedDocument):
to_users = db.ListField(db.ReferenceField(User))
created_at = db.DateTimeField(default=datetime.now)
is_read = db.BooleanField(default=False)
body = db.StringField(required=True)
class Inbox(db.Document):
from_user = db.ReferenceField(User, required=True)
subject = db.StringField(max_length=255, required=True)
created_at = db.DateTimeField(default=datetime.now)
messages = db.ListField(db.EmbeddedDocumentField(Message))
username = User().get_username()
username = User.objects(username=username).first()
inbox = Inbox.objects.filter(messages__to_users__in=[username]).only('from_user', 'subject', 'created_at').to_json()
这是我得到的结果:
[{"created_at": {"$date": 1401593024844}, "from_user": {"$oid": "538ad45fb43fdd69076d3e64"}, "subject": "test"}]
我希望能得到像这样的结果:
[{"created_at": {"$date": 1401593024844}, "from_user": {"username": "holms"}, "subject": "test"}]
或者类似于"from_user" : {"User": {"username":"holms"}}
这样的格式。
更新
上面的回答适用于文档中的ReferenceField,但嵌入文档的引用呢?假设我想在only()中添加“messages”呢?
In [97]: inbox = Inbox.objects(messages__to_users__in=[username]).only('from_user', 'subject', 'created_at', 'messages').select_related()
目前我找到了一种通过映射字典的方法,但这实在是太麻烦了。
In [125]: for entry in inbox:
item = dict(subject=entry.subject, messages=map(lambda msg: dict(body=msg.body, is_read=msg.is_read, to_users=map(lambda usr: usr.username, msg.to_users)), entry.messages), from_user=entry.from_user.username)
result.append(item)
.....:
In [126]: result
Out[126]:
[
{'from_user': u'holms',
'messages': [{'body': u'test body',
'is_read': False,
'to_users': [u'holms']}],
'subject': u'test'}]
更新 2 看起来这个方法有效
57 def to_json(self):
58 data = self.to_mongo() # get pymongo representation
59 data["from_user"] = {"User": {"username": self.from_user.username} }
60
61 for key, reply in enumerate(data["messages"]):
62 for user in self.messages[key].to_users:
63 print user.username
64 reply["to_users"] = {"User": {"username": user.username} }
65
66 return json_util.dumps(data)
然后你就能得到这个结果 :)
{
"_id":{
"$oid":"538ad500b43fdd690e2eefb5"
},
"from_user":{
"User":{
"username":"holms"
}
},
"subject":"test",
"created_at":{
"$date":1401593024844
},
"messages":[
{
"to_users":{
"User":{
"username":"holms"
}
},
"created_at":{
"$date":1401593024845
},
"is_read":false,
"body":"test body"
}
]
}
1 个回答
12
目前,这个功能并不直接支持,因为MongoEngine只支持mongodb的扩展json语法。
MongoEngine背后做的事情其实就是使用pymongo的json_utils
来处理数据。你完全可以直接使用它,比如:
from bson import json_util
class Inbox(db.Document):
from_user = db.ReferenceField(User, required=True)
subject = db.StringField(max_length=255, required=True)
created_at = db.DateTimeField(default=datetime.now)
messages = db.ListField(db.EmbeddedDocumentField(Message))
def to_json(self):
data = self.to_mongo() // get the pymongo representation of the document
data["from_user"] = {"User": {"username": self.from_user.username}}
return json_util.dumps(data)
User.drop_collection()
...
Inbox.drop_collection()
ross = User(username="Ross").save()
Inbox(from_user=ross, subject="Mongoengine should make json easier").save()
doc = Inbox.objects.only('from_user', 'subject', 'created_at').get()
print doc.to_json()
{"_id": {"$oid": "538c3d71c3d384172fe35393"},
"from_user": {"User": {"username": "Ross"}},
"subject": "Mongoengine should make json easier",
"created_at": {"$date": 1401703297198}, "messages": []}
更新
下面是一个使用自定义查询集的例子:
from bson import json_util
class CustomQuerySet(QuerySet):
def to_json(self):
return "[%s]" % (",".join([doc.to_json() for doc in self]))
class Inbox(Document):
from_user = ReferenceField(User, required=True)
subject = StringField(max_length=255, required=True)
created_at = DateTimeField(default=datetime.now)
messages = ListField(EmbeddedDocumentField(Message))
meta = {'queryset_class': CustomQuerySet}
def to_json(self):
data = self.to_mongo()
data["from_user"] = {"User": {"username": self.from_user.username}}
return json_util.dumps(data)
...
ipdb> Inbox.objects.only('from_user', 'subject', 'created_at').to_json()
'[{"_id": {"$oid": "538d84cbc3d3843eeeb5dbbe"},
"from_user": {"User": {"username": "Ross"}},
"subject": "Mongoengine should make json easier",
"created_at": {"$date": 1401787099246}, "messages": []}]'