English ▼
Skip to page content Skip to main navigation
e.g. "templates" or "datastore"

# PolyModel Class

#### Experimental!

NDB is an experimental, innovative, and rapidly changing new feature for App Engine. Unfortunately, being on the bleeding edge means that we may make backwards-incompatible changes to NDB. We will inform the community when this feature is no longer experimental.

The `PolyModel` class lets an application define models that can 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.

It is defined in `google.appengine.ext.ndb.polymodel`.

    from google.appengine.ext import ndb
    from google.appengine.ext.ndb import polymodel

    class Contact(polymodel.PolyModel):
      phone_number = ndb.PhoneNumberProperty()
      address = ndb.PostalAddressProperty()

    class Person(Contact):
      first_name = ndb.StringProperty()
      last_name = ndb.StringProperty()
      mobile_number = ndb.PhoneNumberProperty()

    class Company(Contact):
      name = ndb.StringProperty()
      fax_number = ndb.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.query():
      print 'Phone: %s\nAddress: %s\n\n' % (contact.phone_number, contact.address)

`Contact.query()` returns `Person` and `Company` instances; if `Contact` derived from `Model` instead of from `PolyModel`, each class would have a different `kind` and `Contact.query()` would not return instances of proper subclasses of `Contact`.

If you wish to retrieve only `Person` instances, use `Person.query()`. You could also use `Contact.query(Contact.class_ == 'Person')`.

In addition to the regular Model methods, PolyModel has some interesting class methods:

- `_get_kind()`: the name of the root class; e.g. `Person._get_kind() == 'Contact'`. The root class, Contact in this example, may override this method to use a different name as the kind used in the datastore (for the entire hierarchy rooted here).
- `_class_name()`: the name of the current class; e.g. `Person._class_name() == 'Person'`. A leaf class, Person in our example, may override this method to use a different name as the class name and in the class key. A non-leaf class may also override this method, but beware: its subclasses should also override it, or else they will all use the same class name, and you will soon be very confused.
- `_class_key()`: a list of class names giving the hierarchy. For example, `Person._class_key() == ['Contact', 'Person']`. For deeper hierarchies, this will include all bases between `PolyModel` and the current class, including the latter, but excluding PolyModel itself. This is the same as the value of the `class_` property. Its datastore name is 'class'.

Since the class name is used in the `class_` property and this property is used to distinguish between the subclasses, the class names (as returned by `_class_name()`) should be unique among those subclasses.