与标准 Model 类相比,PolyModel 类让应用能够以更灵活的方式定义支持多态查询的模型。由 PolyModel 派生类生成的查询的结果可以是该类或其任意子类的实例。
该类在 google.appengine.ext.ndb.polymodel 中定义。以下示例展示了 PolyMode 类提供的灵活性。
from google.appengine.ext import ndb from google.appengine.ext.ndb import polymodel class Contact(polymodel.PolyModel): phone_number = ndb.PhoneNumberProperty() address = ndb.PostalAddressProperty() class Person(Contact): first_name = ndb.StringProperty() last_name = ndb.StringProperty() mobile_number = ndb.PhoneNumberProperty() class Company(Contact): name = ndb.StringProperty() fax_number = ndb.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.query(): print 'Phone: %s\nAddress: %s\n\n' % (contact.phone_number, contact.address)
Contact.query() 返回 Person 和 Company 实例;如果 Contact 是从 Model 中派生的(而非从 PolyModel 中),则每个类的 kind 将各不相同,且 Contact.query() 不会返回 Contact 适当子类的实例。
如果您只想检索 Person 实例,请使用 Person.query()。此外,您也可以使用 Contact.query(Contact.class_ == 'Person')。
除了常规的 Model 方法,PolyModel 还有一些有趣的类方法:
_get_kind():根类名称;例如Person._get_kind() == 'Contact'。根类(本示例中的 Contact)可以替换此方法,使用不同的名称作为数据存储区中使用的种类(应用于此处的整个根层次结构)。_class_name():当前类名称;例如Person._class_name() == 'Person'。叶类(本示例中的 Person)可以替换此方法,使用不同的名称作为类名和类键。非叶类也可以替换此方法,但要注意:非叶类的子类也应替换此方法,否则它们都将使用相同的类名,很快就会让你困惑不已。_class_key():提供层次结构的类名列表。例如,Person._class_key() == ['Contact', 'Person']。对于更深的层次结构,这将包括PolyModel和当前类之间的所有基类,其中包含当前类,但不包含 PolyModel 本身。此值与class_属性的值相同。其数据存储区名称为“class”。
由于该类名用于 class_ 属性中,而此属性用于区分子类,因此由 _class_name() 返回的类名在子类中应是唯一的。