Python 2.7 已达到支持终止期限,并将于 2026 年 1 月 31 日
弃用。弃用后,您将无法部署 Python 2.7 应用,即使您的组织之前曾使用组织政策重新启用旧版运行时的部署也是如此。现有的 Python 2.7 应用在
弃用日期之后将继续运行并接收流量。我们建议您
迁移到最新支持的 Python 版本。
PolyModel 类
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
注意:强烈建议构建新应用的开发者使用 NDB 客户端库,它与 DB 客户端库相比具有多项优势,例如可通过 Memcache API 进行自动实体缓存。如果您当前使用的是较早的 DB 客户端库,请参阅 DB 到 NDB 的迁移指南
PolyModel 类是数据模型定义的父类,这些数据模型定义本身也可以是其他数据模型定义的父类。通过 PolyModel 类生成的查询的结果可以是该类或其任意子类的实例。
PolyModel
由 google.appengine.ext.db.polymodel
模块提供。
PolyModel 是 Model 的子类,前者会继承后者的类以及该类中的实例方法。PolyModel 类会覆盖多个 Model 方法,但并不引入任何新的接口元素。
简介
将数据模型定义为分类层次结构往往很有用,这种定义方式类似于对象数据库将一类对象定义为另一类对象的子类。此类数据库可对父类对象执行查询,并在结果中包括子类的对象。App Engine 数据存储区本身不支持这类查询,但是可使用 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
and A
→ C
→ B
。对其中一个层次结构的查询将返回这两个层次结构的实体。同样,对 A
→ B
→ C
和 A
→ C
→ B
的查询在功能上是相同的。最好避免创建具有多个同名节点的单个类层次结构。
PolyModel
不支持覆盖子类中的属性模型定义。如果子类尝试重新定义已在父类中定义的属性,则该类定义将引发 DuplicatePropertyError
。
PolyModel
支持多重继承,包括从共用一个父类的多个类继承(“菱形”继承)。如果两个类为同一属性分别定义一个属性模型定义,则无法从这两个类中继承类(将引发 DuplicatePropertyError
)。不过,如果两个类均已从同一父类中继承相同的属性模型定义,则可以从这两个类中继承类。
与 Expando 一样,PolyModel
不支持动态属性。对于 Expando
,没有等同于 PolyModel
的类。
构造函数
PolyModel 类的构造函数定义如下:
- class PolyModel(parent=None, key_name=None, **kwds)
-
一个模型类,可以是其他模型类的父类,并且其查询可以包含子类实例作为结果。与 Model 类似,必须对 PolyModel 类进行子类化才能定义数据实体的种类。
PolyModel 是 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 类的名称发生了更改,则某个类可覆盖此方法,但实体应继续使用原来的类名称。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-09-04。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["很难理解","hardToUnderstand","thumb-down"],["信息或示例代码不正确","incorrectInformationOrSampleCode","thumb-down"],["没有我需要的信息/示例","missingTheInformationSamplesINeed","thumb-down"],["翻译问题","translationIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-09-04。"],[[["\u003cp\u003eThe \u003ccode\u003ePolyModel\u003c/code\u003e class allows for the creation of data model hierarchies, enabling queries to include instances of both the base class and its subclasses.\u003c/p\u003e\n"],["\u003cp\u003e\u003ccode\u003ePolyModel\u003c/code\u003e classes are stored in the datastore under the root class name, and each entity stores its class hierarchy in a \u003ccode\u003e'class'\u003c/code\u003e property, which is used for query filtering.\u003c/p\u003e\n"],["\u003cp\u003eSubclasses of \u003ccode\u003ePolyModel\u003c/code\u003e can introduce new properties but cannot override properties defined in parent classes, raising a \u003ccode\u003eDuplicatePropertyError\u003c/code\u003e if attempted.\u003c/p\u003e\n"],["\u003cp\u003ePolymorphic queries on \u003ccode\u003ePolyModel\u003c/code\u003e require indexes that include the \u003ccode\u003e'class'\u003c/code\u003e property and they support equality filters and can be combined with other filters.\u003c/p\u003e\n"],["\u003cp\u003e\u003ccode\u003ePolyModel\u003c/code\u003e supports multiple inheritance but not dynamic properties or \u003ccode\u003eExpando\u003c/code\u003e, and it's recommended to avoid multiple nodes with same name in class hierarchies.\u003c/p\u003e\n"]]],[],null,["# The PolyModel Class\n\n**Note:**\nDevelopers building new applications are **strongly encouraged** to use the\n[NDB Client Library](/appengine/docs/legacy/standard/python/ndb), which has several benefits\ncompared to this client library, such as automatic entity caching via the Memcache\nAPI. If you are currently using the older DB Client Library, read the\n[DB to NDB Migration Guide](/appengine/docs/legacy/standard/python/ndb/db_to_ndb)\n\nThe PolyModel class is the superclass for data model definitions that can themselves be superclasses for other data model definitions. A query produced from a PolyModel class can have results that are instances of the class or any of its subclasses.\n\n`PolyModel` is provided by the `google.appengine.ext.db.polymodel` module.\n\nPolyModel is a subclass of [Model](/appengine/docs/legacy/standard/python/datastore/modelclass), and inherits its class and instance methods from that class. The PolyModel class overrides several of Model's methods, but does not introduce any new interface elements.\n\nIntroduction\n------------\n\nIt is often useful to define data models as a classification hierarchy, much like how an object database can define one class of objects as a sub-class of another. Such a database can perform queries on objects of the parent class, and include objects of the sub-class in the results. The App Engine datastore does not support this kind of query natively, but you can implement it using a mechanism included with the Python SDK, the `PolyModel` class.\n\nA model class derived from `PolyModel` can be the base class for other model classes. Queries created for these classes using the `all()` and `gql()` methods know to include instances of subclasses in the results.\n\nSubclasses can define new properties not present on parent classes. However, subclasses cannot override property definitions of parent classes. (Doing so results in a `DuplicateProperty` error.)\n\nFor reference, here is the simple example from [Entities and Models](/appengine/docs/legacy/standard/python/datastore/datamodeling). Notice that the `PolyModel` class is provided by the package `google.appengine.ext.db.polymodel`. \n\n```python\nfrom google.appengine.ext import db\nfrom google.appengine.ext.db import polymodel\n\nclass Contact(polymodel.PolyModel):\n phone_number = db.PhoneNumberProperty()\n address = db.PostalAddressProperty()\n\nclass Person(Contact):\n first_name = db.StringProperty()\n last_name = db.StringProperty()\n mobile_number = db.PhoneNumberProperty()\n\nclass Company(Contact):\n name = db.StringProperty()\n fax_number = db.PhoneNumberProperty()\n\np = Person(phone_number='1-206-555-9234',\n address='123 First Ave., Seattle, WA, 98101',\n first_name='Alfred',\n last_name='Smith',\n mobile_number='1-206-555-0117')\np.put()\n\nc = Company(phone_number='1-503-555-9123',\n address='P.O. Box 98765, Salem, OR, 97301',\n name='Data Solutions, LLC',\n fax_number='1-503-555-6622')\nc.put()\n\nfor contact in Contact.all():\n # Returns both p and c.\n # ...\n\nfor person in Person.all():\n # Returns only p.\n # ...\n```\n\nPolymorphism is not a native feature of the datastore. Instead, polymorphism is implemented in the `PolyModel` class itself. All entities created from `PolyModel` subclasses are stored in the datastore with the same kind, which is the name of the root class (e.g. `Animal`). Each object stores its class hierarchy as a multi-valued property of the entity named `'class'`. When the app creates a query using a `PolyModel` class's `all()` or `gql()` method, the query includes a filter on the `'class'` property that limits the results to entities created from the class or any subclass.\n\nBecause `PolyModel` uses a property of the entity to store class information, indexes for polymorphic queries must accommodate the `'class'` property. The implied filter is an equality filter, and can be combined with other equality filters and inequality filters on other properties.\n\n**Note:** PolyModel uses just the names of the classes in the `'class'` property, not full paths. It's possible to create class hierarchies with multiple nodes of the same name, such as `A` → `B` and `A` → `C` → `B`. A query for one will return entities of both. Similarly, queries for `A` → `B` → `C` and `A` → `C` → `B` are functionally identical. It's best to avoid creating a single class hierarchy with multiple nodes of the same name.\n\n`PolyModel` does not support overriding property model definitions in subclasses. If a subclass tries to redefine a property that is defined on a superclass, the class definition raises a `DuplicatePropertyError`.\n\n`PolyModel` supports multiple inheritance, including inheriting from multiple classes that share a superclass (\"diamond\" inheritance). A class cannot inherit from two classes that each define a property model definition for the same property (this would raise a `DuplicatePropertyError`). However, a class can inherit from two classes that inherit the same property model definition from the same superclass.\n\n`PolyModel` does not support dynamic properties, like [Expando](/appengine/docs/legacy/standard/python/datastore/expandoclass) does. There is not an equivalent of `PolyModel` for `Expando`.\n\nConstructor\n-----------\n\nThe constructor of the PolyModel class is defined as follows:\n\nclass PolyModel(parent=None, key_name=None, \\*\\*kwds)\n\n: A model class that can be a superclass to other model classes, and whose queries can include instances of subclasses as results. Like [Model](/appengine/docs/legacy/standard/python/datastore/modelclass), the PolyModel class must be subclassed to define the kind of the data entities.\n\n PolyModel is a subclass of [Model](/appengine/docs/legacy/standard/python/datastore/modelclass), and inherits or overrides its methods.\n\n Arguments\n\n parent\n : The Model instance or Key instance for the entity that is the new entity's parent.\n\n key_name\n\n : The name for the new entity. The name becomes part of the primary key. If `None`, a system-generated ID is used for the key.\n\n The value for key_name must not start with a number, and must not be of the form `__*__`. If your application uses user-submitted data as datastore entity key names (such as an email address), the application should sanitize the value first, such as by prefixing it with a known string like \"key:\", to meet these requirements.\n\n A `key_name` is stored as a Unicode string, with `str` values converted as ASCII text.\n\n \\*\\*kwds\n : Initial values for the instance's properties, as keyword arguments. Each name corresponds with an attribute of the new instance, and must correspond with fixed properties defined in the PolyModel class.\n\nClass Methods\n-------------\n\nIn addition to the class methods defined by the [Model](/appengine/docs/legacy/standard/python/datastore/modelclass) class, the PolyModel class provides the following class methods:\n\nPolyModel.class_key()\n\n: Returns the name of the class and the names of all parent classes for the class, as a tuple.\n\nPolyModel.class_name()\n\n: Returns the name of the class. A class can override this method if the name of the Python class changes, but entities should continue using the original class name."]]