Support for polymorphic models and queries.
The Model class on its own is only able to support functional polymorphism. It is possible to create a subclass of Model and then subclass that one as many generations as necessary and those classes will share all the same properties and behaviors. The problem is that subclassing Model in this way places each subclass in their own Kind. This means that it is not possible to do polymorphic queries. Building a query on a base class will only return instances of that class from the Datastore, while queries on a subclass will only return those instances.
This module allows applications to specify class hierarchies that support polymorphic queries.
- class google.appengine.ext.db.polymodel.PolyModel(parent=None, key_name=None, _app=None, _from_entity=False, **kwds)source
Base-class for models that supports polymorphic queries.
Use this class to build hierarchies that can be queried based on their types.Example
consider the following model hierarchy:
+------+ +------+ |Canine||Feline| +------+ +------+|
+-------+ +-------+ | | | |
+---+ +----+ +---+ +-------+ |Dog||Wolf||Cat||Panther| +---+ +----+ +---+ +-------+
This class hierarchy has three levels. The first is the "root class". All models in a single class hierarchy must inherit from this root. All models in the hierarchy are stored as the same kind as the root class. For example, Panther entities when stored to the datastore are of the kind 'Animal'. Querying against the Animal kind will retrieve Cats, Dogs and Canines, for example, that match your query. Different classes stored in the root class' kind are identified by their class-key. When loaded from the datastore, it is mapped to the appropriate implementation class.
Properties that are defined in a given base-class within a hierarchy are stored in the datastore for all sub-casses only. So, if the Feline class had a property called 'whiskers', the Cat and Panther enties would also have whiskers, but not Animal, Canine, Dog or Wolf.
When written to the datastore, all polymorphic objects automatically have a property called 'class' that you can query against. Using this property it is possible to easily write a GQL query against any sub-hierarchy. For example, to fetch only Canine objects, including all Dogs and Wolves:
db.GqlQuery("SELECT * FROM Animal WHERE class='Canine'")
And alternate method is to use the 'all' or 'gql' methods of the Canine class:
The 'class' property is not meant to be used by your code other than for queries. Since it is supposed to represents the real Python class it is intended to be hidden from view.
The root class is the class from which all other classes of the hierarchy inherits from. Each hierarchy has a single root class. A class is a root class if it is an immediate child of PolyModel. The subclasses of the root class are all the same kind as the root class. In other words:
Animal.kind() == Feline.kind() == Panther.kind() == 'Animal'
- classmethod all(**kwds)source
Get all instance of a class hierarchy.Parameters
kwds -- Keyword parameters passed on to Model.all.Returns
Query with filter set to match this class' discriminator.
- classmethod class_key()source
Calculate the class-key for this class.Returns
Class key for class. By default this is a the list of classes of the hierarchy, starting with the root class and walking its way down to cls.
- classmethod class_name()source
Calculate class name for this class.
Returns name to use for each classes element within its class-key. Used to discriminate between different classes within a class hierarchy's Datastore kind.
The presence of this method allows developers to use a different class name in the datastore from what is used in Python code. This is useful, for example, for renaming classes without having to migrate instances already written to the datastore. For example, to rename a polymorphic class Contact to SimpleContact, you could convert:
# Class key is ['Information'] class Information(PolyModel): ...
# Class key is ['Information', 'Contact'] class Contact(Information): ...
# Class key is still ['Information', 'Contact'] class SimpleContact(Information):
... @classmethod def class_name(cls):
# Class key is ['Information', 'Contact', 'ExtendedContact'] class ExtendedContact(SimpleContact): ...
This would ensure that all objects written previously using the old class name would still be loaded.Returns
Name of this class.
- classmethod from_entity(entity)source
Load from entity to class based on discriminator.
Rather than instantiating a new Model instance based on the kind mapping, this creates an instance of the correct model class based on the entities class-key.Parameters
entity -- Entity loaded directly from datastore.Raises
KindError when there is no class mapping based on discriminator.
- classmethod gql(query_string, *args, **kwds)source
Returns a polymorphic query using GQL query string.
This query is polymorphic in that it has its filters configured in a way to retrieve instances of the model or an instance of a subclass of the model.Parameters
query_string -- properly formatted GQL query string with the 'SELECT * FROM <entity>' part omitted
*args -- rest of the positional arguments used to bind numeric references in the query.
**kwds -- dictionary-based arguments (for named parameters).
- classmethod kind()source
Get kind of polymorphic model.
Overridden so that all subclasses of root classes are the same kind as the root.Returns
Kind of entity to write to datastore.
- class google.appengine.ext.db.polymodel.PolymorphicClass(name, bases, dct)source
Meta-class for initializing PolymorphicClasses.
This class extends PropertiedClass to add a few static attributes to new polymorphic classes necessary for their correct functioning.