附註:我們強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,因為 NDB 用戶端程式庫與本用戶端程式庫相較之下有幾個優點,例如能透過 Memcache API 自動將實體加入快取。如果您目前使用的是舊版的 DB 用戶端程式庫,請參閱從 DB 至 NDB 的遷移指南。
有些資料模型定義本身可以是其他資料模型定義的超類別,而 PolyModel 類別是這類資料模型定義的超類別。如果是透過 PolyModel 類別產生的查詢,其結果可能是該類別或其任何子類別的例項。
PolyModel
由 google.appengine.ext.db.polymodel
模組提供。
PolyModel 是 Model 的子類別,會沿用 Model 類別的類別和例項方法。PolyModel 類別會覆寫 Model 的幾種方法,但不會導入任何新的介面元素。
簡介
將資料模型定義為分類階層 (如同物件資料庫可將某一物件類別定義為其他類別的子類別),往往可帶來好處。這類資料庫可對父項類別的物件執行查詢,並在結果中加入子類別的物件。App Engine Datastore 並未原生支援這類查詢,但您可以使用 Python SDK 隨附的機制 (PolyModel
類別) 實作這類查詢。
衍生自 PolyModel
的模型類別可做為其他模型類別的基本類別。使用 all()
和 gql()
方法為這些類別建立的查詢,會知道要在結果中加入子類別的例項。
子類別可定義父項類別中沒有的新屬性。不過,子類別無法覆寫父項類別的屬性定義 (這麼做會導致 DuplicateProperty
錯誤)。
以下提供實體和模型一文中的簡易範例供您參考。請注意,PolyModel
類別是由 google.appengine.ext.db.polymodel
套件提供。
from google.appengine.ext import db from google.appengine.ext.db import polymodel class Contact(polymodel.PolyModel): phone_number = db.PhoneNumberProperty() address = db.PostalAddressProperty() class Person(Contact): first_name = db.StringProperty() last_name = db.StringProperty() mobile_number = db.PhoneNumberProperty() class Company(Contact): name = db.StringProperty() fax_number = db.PhoneNumberProperty() p = Person(phone_number='1-206-555-9234', address='123 First Ave., Seattle, WA, 98101', first_name='Alfred', last_name='Smith', mobile_number='1-206-555-0117') p.put() c = Company(phone_number='1-503-555-9123', address='P.O. Box 98765, Salem, OR, 97301', name='Data Solutions, LLC', fax_number='1-503-555-6622') c.put() for contact in Contact.all(): # Returns both p and c. # ... for person in Person.all(): # Returns only p. # ...
「多型」並非資料儲存庫的原生功能,而是在 PolyModel
類別本身中實作多型化。從 PolyModel
子類別建立的所有實體都會以相同的種類儲存在資料儲存庫中,也就是根類別的名稱 (例如 Animal
)。每個物件都會將其類別階層儲存為名為 'class'
的實體多值屬性。當應用程式使用 PolyModel
類別的 all()
或 gql()
方法建立查詢時,查詢會在 'class'
屬性上加入篩選器,將結果限制為從該類別或任何子類別建立的實體。
由於 PolyModel
會使用實體的屬性來儲存類別資訊,因此多型查詢的索引必須支援 'class'
屬性。系統採用的篩選器是等式篩選器,並可與其他等式篩選器和不等式篩選器結合,以用於其他屬性。
注意:PolyModel 只會使用 'class'
屬性中的類別名稱,而不會使用完整路徑。您可以建立類別階層,其中包含多個同名節點,例如 A
→ B
和 A
→ C
→ B
。對其中一個階層執行查詢會傳回兩者的實體。同樣地,A
→ B
→ C
和 A
→ C
→ B
的查詢功能相同。建議您避免使用多個名稱相同的節點來建立單一類別階層。
PolyModel
不支援在子類別中覆寫屬性模型定義。如果子類別嘗試重新定義在父類別中定義的屬性,則類別定義會擲回 DuplicatePropertyError
。
PolyModel
支援多重繼承,包括從共用超類別的多個類別繼承 (稱為「菱形」繼承)。如有兩個類別分別針對相同屬性定義了不同屬性模型定義,則類別不得繼承這兩個類別,否則會發生 DuplicatePropertyError
。不過,如有兩個類別繼承了相同超類別的屬性模型定義,類別就可繼承這兩個類別。
PolyModel
與 Expando 相同,不支援動態屬性。Expando
沒有 PolyModel
的等效函式。
建構函式
PolyModel 類別的建構函式定義如下:
- class PolyModel(parent=None, key_name=None, **kwds)
-
模型類別可以是其他模型類別的超類別,且其查詢結果可包含子類別的例項。如同 Model,PolyModel 類別必須變成子類別才能定義資料實體的種類。
PolyModel 是 Model 的子類別,會沿用或覆寫 Model 類別的方法。
引數
- parent
- 實體 (為新實體的父項) 的 Model 例項或 Key 例項。
- key_name
-
新實體的名稱。這個名稱會成為主要金鑰的一部分。如果值為
None
,系統會使用系統產生的 ID 做為金鑰。key_name 值的開頭不得為數字,且格式不得為
__*__
。如果您的應用程式是以使用者提交的資料做為資料儲存庫實體金鑰名稱 (例如電子郵件地址),應用程式應先對值進行處理以滿足這些要求,例如在前方加上「key:」等已知字串。key_name
會以 Unicode 字串形式儲存,其中str
值會轉換成 ASCII 文字。 - **kwds
- 例項屬性的初始值,形式為關鍵字引數。每個名稱會對應到新例項的屬性,且必須對應到 PolyModel 類別中定義的固定屬性。
類別方法
除了 Model 類別定義的類別方法,PolyModel 類別還提供下列類別方法:
- PolyModel.class_key()
-
傳回類別的名稱和所有父項類別的名稱,以元組表示。
- PolyModel.class_name()
-
傳回類別的名稱。如果 Python 類別的名稱有所異動,類別可覆寫這個方法,但實體應繼續使用原始類別名稱。