Python 2.7 已終止支援,並將於 2026 年 1 月 31 日
淘汰。淘汰後,您將無法部署 Python 2.7 應用程式,即使貴機構先前曾使用機構政策重新啟用舊版執行階段的部署作業,也無法部署。現有的 Python 2.7 應用程式在
淘汰日期過後,仍會繼續執行並接收流量。建議您
改用系統支援的最新 Python 版本。
PolyModel 類別
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
附註:我們強烈建議建構新應用程式的開發人員使用 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 類別的名稱有所異動,類別可覆寫這個方法,但實體應繼續使用原始類別名稱。
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間: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"]],["上次更新時間: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."]]