2013-04-04 59 views
0

我有一個相當重要的文檔類User,我想將它分成兩部分:UserProfile文檔中的用戶配置文件(名稱和頭像),其餘部分位於User文檔中,如下所示(使用MongoEngine):如何使用MongoEngine ReferenceField爲2個集合使用相同的ObjectId?

from mongoengine import * 

class User(Document): 
    login = StringField() 
    password = StringField() 
    posts = ListField(ReferenceField("Post", dbref = False)) 
    #... a bunch of other fields 

class UserProfile(Document): 
    name = StringField() 
    avatar = URLField() 

我想爲UserProfile和User都有相同的ObjectId,這樣我只需要一個ObjectId即可引用User和UserProfile。畢竟,這實際上是一對一的關係,並且由於用戶可以創作很多帖子,所以我不想將自己的個人資料嵌入到帖子本身中。在創建用戶文檔時,我會立即創建如下所示的相應配置文件:

john = User.objects.create(login = "john", password = "super!password") 
john_profile = UserProfile.objects.create(id = john.id, name = "John Smith", 
       avatar = "http://www.example.com/img/photo.jpg") 

到目前爲止這麼好。現在我有一個Post文檔與author場引用User文件:

class Post(Document): 
    author = ReferenceField("User", dbref = False) 
    text = StringField() 

我想補充一個author_profile參考,基於相同的ObjectId。我嘗試這樣做:

class Post(Document): 
    author = ReferenceField("User", dbref = False) 
    author_profile = ReferenceField("User", db_field = "author", dbref = False) 
    text = StringField() 

,但我得到以下異常:

mongoengine.base.InvalidDocumentError: Multiple db_fields defined for: author 

如此看來,我不得不如此「手工」做。也許這樣的事情:

class Post(Document): 
    author = ReferenceField("User", dbref = False) 
    text = StringField() 
    @property 
    def author_profile(self): 
     if hasattr(self, "_author_profile"): 
      return self._author_profile 
     self._author_profile = UserProfile.objects.get(id = self._data["author"].id) 
     return self._author_profile 

我想這並不壞,但是沒有更好的解決方案嗎?

謝謝。

注意:我讀了關於一對一關係的mongodb documentation以及mongoengine ReferenceField documentation,但它並沒有幫助我解決這個具體問題。

+0

爲什麼你不使用登錄(我認爲它是唯一的)爲_id? – 2013-04-05 12:12:09

+0

是的,我可以,你是對的,但我不認爲它解決了我的問題:我將如何實現'post.author'和'post.author_profile'?我需要兩個ReferenceFields,一個指向User,另一個指向UserProfile,它們都具有相同的ID(無論是objectid還是login)。你看到我的觀點了嗎? – MiniQuark 2013-04-05 19:25:03

+0

我從來沒有與mongoengine合作過,所以不幸的是我無法幫助你。另外,我不喜歡使用DBRef,因爲我更喜歡手動控制關係。我不知道你是否對mongodb是陌生的,但需要記住的一點是,關係數據庫不是設計數據。 – 2013-04-09 11:41:47

回答

0

你不得不存儲相同的ID兩次做到這一點:

class Post(Document): 
    author = ReferenceField("User", dbref = False) 
    author_profile = ReferenceField("UserProfile", dbref = False) 
    text = StringField() 

我不知道,如果是帶給您的解決方案的任何利益 - 有可能在查詢中取消引用數的改進,但我必須測試一下!

0

我結束了寫這個:

def user_profile(reference_name): 
    attrib_name = "_" + reference_name + "_profile" 
    def user_profile_getter(self): 
     if not hasattr(self, attrib_name): 
      reference = self._data.get(reference_name, None) 
      if not reference: 
       return None 
      setattr(self, attrib_name, UserProfile.objects.get(reference.id)) 
     return getattr(self, attrib_name) 
    return property(user_profile_getter) 

Post類現在看起來是這樣的:

class Post(Document): 
    author = ReferenceField("User", dbref = False) 
    author_profile = user_profile("author") 
    text = StringField() 

每當我添加ReferenceField指向User類,我也添加這樣一個user_profile (只讀)參考。請注意,如果您只訪問author_profile,則不會加載author,反之亦然。

相關問題