1

我試圖使用Expando模型作爲另一個模型重複StructuredProperty。也就是說,我想在我的User型號上添加無限數Accounts。作爲Accounts可以根據自己的類型有不同的特性(Accounts是社交網絡帳戶的引用,例如Twitter的需要比Facebook更多的信息,其OAuth的過程),我設計我的Account模型作爲Expando。我已經在模型定義中添加了所有基本信息,但是我打算爲特定社交網絡添加自定義屬性(例如,Twitter的特定access_token_secret屬性)。自定義屬性不正確保存爲Expando的模型反覆StructuredProperty

1 /您能否確認以下設計(Expando重複StructuredProperty應該能工作嗎?

class Account(ndb.Expando): 
    account_type = ndb.StringProperty(required=True, choices=['fb', 'tw', 'li']) 
    account_id = ndb.StringProperty() 
    state = ndb.StringProperty() 
    access_token = ndb.StringProperty() 

class HUser(User): 
    email = ndb.StringProperty(required=True, validator=validate_email) 
    created = ndb.DateTimeProperty(auto_now_add=True) 
    accounts = ndb.StructuredProperty(Account, repeated=True) 

2 /現在我面臨的問題是:當我添加一個Facebook帳戶,以我的HUser情況下,一切工作正常;

for account in huser.accounts: 
    if account.state == "state_we_re_looking_for" and account.account_type == 'tw': 
     # we found the appropriate Twitter account reference 
     account.access_token_secret = "..." # store the access token secret fetched from Twitter API 
     huser.put() # save to the Datastore 
     break 

這個操作應該保存訪問令牌密鑰在Twitter的Account:然而,當我附上一個Twitter帳戶,以同樣的實例,並添加在模型中沒有宣佈一個新的屬性,這樣的問題上升我User的實例,但實際上它保存到了Facebook的Account實例(索引0)!

我在做什麼錯?

謝謝。

回答

1

這是怎麼NDB存儲StructuredProperty一個根本性的問題。數據存儲目前沒有辦法存儲這個,所以ndb基本上爆炸你的屬性。

例如,考慮實體:

HUser(email='[email protected]'. 
     accounts=(Account(type='fb', 
         account_id='1', 
         state='1', 
         access_token='1'), 
       Account(type='tw', 
         account_id='2', 
         state='2', 
         access_token='2', 
         access_token_secret='2'))) 

這實際上獲取存儲在看起來像一個實體:

{ 
email : '[email protected]', 
accounts.type : ['fb', 'tw'], 
accounts.account_id : ['1', '2'], 
accounts.state : ['1', '2'], 
accounts.access_token : ['1', '2'], 
accounts.access_token_secret : ['2'] 
} 

由於您使用的是ndb.Expando,NDB不知道它應該填充access_token_secret字段的facebook賬戶None。當ndb重新填充您的實體時,它將填入access_token_secret爲它看到的第一個帳戶,這是Facebook帳戶。

重組你的數據聽起來像正確的方式去了解這一點,但你可能想使你的HUser的Account的祖先爲HUser,讓你查詢使用strong consistency用戶的帳戶。

+0

哇...我想選擇我自己的答案作爲正確的答案,但是你的答案要詳細得多,謝謝!至於你的最後一個建議,我會研究它,但我有一個問題:如果我創建了具有對應的'HUser'的祖先引用的'Account'實體,我的'Account'模型應該成爲什麼?我想我可以安全地刪除我在我的回答中提到的'KeyProperty',但是我應該聲明關於祖先的任何內容嗎?如果不是,那麼這意味着祖先將不是強制性的,我可能會忘記在將來設置一個? – Romain

+1

在創建帳戶時,沒有任何方法可以聲明祖先,而不是設置它。你說得對,這可能更容易出錯(因爲你不能將其標記爲強制性的)。然而,在這一點上,您應該使用如下查詢訪問用戶的所有帳戶:'Account.query(ancestor = huser.key)'。所以,如果你忘記設置祖先,你應該注意到這種新型的賬戶沒有出現。更重要的是,這是非常一致的,所以你可以保證你將永遠得到一個用戶的所有賬戶。 –

+1

另一個想法 - 您可以隨時在您的'HUser'模型中添加一個方法來添加一個帳戶。至少,'Account's將始終在'HUser'的上下文中創建。像這樣的https://github.com/proppy/appengine-todos-flask/commit/ef582ccfe7f468604e4dad0ab563f896268aaad9#diff-fafd174e32950faa08cce18610c43170R74(抱歉,鏈接到正在進行的代碼)。 –

1

從我所瞭解的情況來看,似乎App Engine NDB不支持Expando實體本身包含Expando實體。

有一件事我起初並沒有意識到,我的HUser型號繼承自Google的User類,這正是Expando型!

所以甚至不知道它,我試圖把一個重複內的另一個ExpandoExpandoStructuredProperty對象,這看似支持(我沒有發現任何清晰的寫在這個限制,不過)。

解決方案是以不同的方式設計數據模型。我把我的Account對象在一個單獨的實體類型(而這一次,他們是真正的Expando對象!),和我添加了一個KeyProperty引用HUser實體。這涉及到更多的讀/寫OPS,但代碼實際上是要簡單得多,現在讀...

我會記住我自己的問題作爲回答,除非有人就發現這裏的限制了另一個有趣的輸入。

+0

我認爲這是提到。 https://developers.google.com/appengine/docs/python/ndb/properties?hl=nl#structured。 如果我是正確的,並正確理解你的情況 –

+1

你是指黃色段?它確實表明你不能在另一個重複的'StructuredProperty'中嵌套重複的'StructuredProperty',但是對'Expando'模型沒有任何說法。或者我是盲人? :) – Romain

+0

對不起,可能是我參考的錯誤。將嘗試重現它。 –

相關問題