The PolyModel Class

Note: Developers building new applications are strongly encouraged to use the NDB Client Library, which has several benefits compared to this client library, such as automatic entity caching via the Memcache API. If you are currently using the older DB Client Library, read the DB to NDB Migration Guide

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.

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 AB and ACB. A query for one will return entities of both. Similarly, queries for ABC and ACB 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, with str 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.