The 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.
PolyModel
is provided by the
google.appengine.ext.db.polymodel
module.
- Introduction
- PolyModel()
- Class methods:
PolyModel is a subclass of Model , 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.
Introduction
It 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.
A 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.
Subclasses 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.)
For reference, here is the simple example from
Entities and Models
. Notice that the
PolyModel
class is provided by the package
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. # ...
Polymorphism 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.
Because
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.
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.
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
.
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.
PolyModel
does not support dynamic properties, like
Expando
does. There is not an equivalent of
PolyModel
for
Expando
.
Constructor
The constructor of the PolyModel class is defined as follows:
- class PolyModel ( parent = None , key_name = None , ** kwds )
-
A model class that can be a superclass to other model classes, and whose queries can include instances of subclasses as results. Like Model , the PolyModel class must be subclassed to define the kind of the data entities.
PolyModel is a subclass of Model , and inherits or overrides its methods.
Arguments
- parent
- The Model instance or Key instance for the entity that is the new entity's parent.
- key_name
-
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.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.A
key_name
is stored as a Unicode string, withstr
values converted as ASCII text. - ** kwds
- 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.
Class Methods
In addition to the class methods defined by the Model class, the PolyModel class provides the following class methods:
- PolyModel.class_key ()
-
Returns the name of the class and the names of all parent classes for the class, as a tuple.
- PolyModel.class_name ()
-
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.