Skip to page content Skip to main navigation
English | Site Directory

e.g. "templates" or "datastore"

# The PolyModel Class

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.class_key()
  - PolyModel.class_name()

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.
      # ...

`PolyModel` does not support dynamic properties, like Expando does. There is not an equivalent of `PolyModel` for `Expando`.

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.

## Constructor

The constructor of the PolyModel class is defined as follows:

class PolyModel(parent=None, key_name=None, **kw)

  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.

  **kw
    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.