官方文件中提過不少的技巧,這裏就說一說官方文件中沒有記載的,第一個是關於ReferenceProperty的自動載入、轉換。
參考以下代碼:
class Author(db.Model):ReferenceProperty類別的模型為金鑰值(db.Key()),指向其他的記錄。以上叫做Story的模型有一個叫做author的ReferenceProperty,代表該故事的作者,而作者的資料則記錄在Author模型中,這種做法在SQL資料庫裏也很常見,沒什麼特別。
name = db.StringProperty()
class Story(db.Model):
author = db.ReferenceProperty(Author)
story = db.get(story_key)
author_name = story.author.name
story = db.get(story_key)這句在BigTable中取得一項Story記錄(又或者叫做實體模型、Model instance),要留意就是story.author_name所儲存的只是Key,並不包括作者的姓名等記錄在Author的資料。
author_name = story.author.name當執行了以上的命令時,author_name儲存了什麼呢?答案是Author的實體的模型(model instance),並非以上所說的Key值。
這是ReferenceProperty的「功能」,一項自動載入、轉換的能力,跟據說明文件:
「ReferenceProperty 屬性值可以當做被參考實體的模型實例來使用。若參考的實體不在記憶體中,使用其屬性做為實例時,會自動從資料存放區擷取該實體。Source : http://code.google.com/intl/en/appengine/docs/python/datastore/entitiesandmodels.html#References
A ReferenceProperty property value can be used as if it were the model instance of the referenced entity. If the referenced entity is not in memory, using the property as an instance automatically fetches the entity from the datastore.」
故此在story.author_name被第一次存取時,GAE就會自動在資料庫中取出記錄,很方便的功能吧?但別忘了,這會存取資料庫,代表會消耗有限的配額。
如果真的需要到這項資料,消耗也是沒有辦法的,但如果在其他的query中已取得這項Author的實體模型,也就冤枉了。
另外有種情況也會造成無辜的消耗,就是創建URL時,現在很喜歡這樣的URL風格:
xxxxxxx/$author_id/$story_id當author_id=768,story_id = 10045時,就會變成是:
xxxxxxx/768/10045假設在你的程式裏,已經擁有一個Story的實體,然後你想輸出以上的URL,基於需要用到Author的ID,你可能會這樣寫:
author_id = story.author_name.key().id_or_name()而很不幸地,雖然在Story的實體中有記錄Author的Key,但這種寫法會導至GAE進行一次資料庫存取 - 浪費了配額下載了你不需要的資料。
這時候需要迂迴一點的寫法:
property = getattr(Story, "author_name")這樣就不會造成資料庫的存取,為你省下不少的配額。
author_key = property.get_value_for_datastore(story)
author_id = author_key.id_or_name()
註: getattr(story,"author_name")的結果也是會導至資料庫的讀取
沒有留言:
發佈留言