【问题标题】:How to get ReferenceField data in mongoengine?如何在 mongoengine 中获取 ReferenceField 数据?
【发布时间】:2014-06-01 08:16:01
【问题描述】:

我在查询集检索 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"}}

更新

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

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'}]

UPDATE 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"
          }
       ]

    }

【问题讨论】:

  • 你在使用 Django 吗?
  • 不,我正在使用烧瓶。我们拥有的最好的是flask-mongoengine。您建议的 select_related() 解决方案不好?剩下的就是将其转换为 json..

标签: python mongodb mongoengine


【解决方案1】:

目前不直接支持,因为 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": []}]'

【讨论】:

  • 是否可以对 filter() 做同样的事情?我需要物品清单。当用过滤器“to_json()”替换 get() 时,甚至不再可调用。我的意思是调用该方法甚至不执行它,我已经检查过 print..
  • 使用filter,您必须收集 json 文档,例如:"[%s]" % (",".join([doc.to_json() for doc in docs]))
  • 使用自定义查询集示例更新了答案
  • 在使用 QuerySet 创建 CustomQuerySet from (from flask.ext.mongoengine import QuerySet OR from from mongoengine import QuerySet) “我输了”方法 get_or_404 因为它不存在于引用的类中。我解决了从 flask.ext.mongoengine import BaseQuerySet 导入
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 2014-02-09
  • 1970-01-01
  • 1970-01-01
  • 2018-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多