如何在mongoengine中获取ReferenceField数据?

hol*_*lms 5 python mongodb mongoengine

我有一个问题,查询集oid在json中检索,我想检索我在下面的User集合的实际用户名:

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()
Run Code Online (Sandbox Code Playgroud)

这就是我得到的结果:

[{"created_at": {"$date": 1401593024844}, "from_user": {"$oid": "538ad45fb43fdd69076d3e64"}, "subject": "test"}]
Run Code Online (Sandbox Code Playgroud)

有这样的事情会很高兴:

[{"created_at": {"$date": 1401593024844}, "from_user": {"username": "holms"}, "subject": "test"}]
Run Code Online (Sandbox Code Playgroud)

或者某种类似的相似 "from_user" : {"User": {"username":"holms"}}

UPDATE

上面的答案适用于Document中的ReferenceField,但是EmbeddedDocument引用呢?假设我只将"消息"添加到()?

In [97]: inbox = Inbox.objects(messages__to_users__in=[username]).only('from_user', 'subject', 'created_at', 'messages').select_related()
Run Code Online (Sandbox Code Playgroud)

目前我通过映射字典找到了方法,这非常痛苦.

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'}]
Run Code Online (Sandbox Code Playgroud)

更新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)
Run Code Online (Sandbox Code Playgroud)

你得到这个:)

    {
       "_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"
          }
       ]

    }
Run Code Online (Sandbox Code Playgroud)

Ros*_*oss 6

目前不支持直接,因为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": []}
Run Code Online (Sandbox Code Playgroud)

更新

自定义查询集的示例:

   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": []}]'
Run Code Online (Sandbox Code Playgroud)