Eine Anwendung kann mit der Klasse PolyModel
Modelle definieren, die polymorphe Abfragen flexibler unterstützen als die Standard-Model
-Klasse.
Eine über eine abgeleitete PolyModel
-Klasse erstellte Abfrage kann im Ergebnis zu Instanzen der Klasse oder ihrer abgeleiteten Klassen führen.
Dies wird in google.appengine.ext.ndb.polymodel
definiert. Im folgenden Beispiel wird deutlich, wie flexibel die PolyModel-Klasse verwendet werden kann.
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()
gibt Person
- und Company
-Instanzen zurück. Wenn Contact
von Model
anstatt von PolyModel
abgeleitet wird, hat jede Klasse einen anderen kind
-Wert und Contact.query()
gibt keine Instanzen der korrekten abgeleiteten Klassen von Contact
zurück.
Wenn Sie nur Person
-Instanzen abrufen möchten, verwenden Sie Person.query()
. Mit Contact.query(Contact.class_ == 'Person')
ist dies ebenfalls möglich.
PolyModel bietet außerdem neben den regulären Model-Methoden hilfreiche Klassenmethoden:
_get_kind()
: der Name der Stammklasse, z. B.Person._get_kind() == 'Contact'
. Die Stammklasse – in diesem Beispiel "Contact" – kann diese Methode überschreiben, um einen anderen Namen als im Datenspeicher zu verwenden. Dies gilt für die gesamte Hierarchie unterhalb der Stammklasse._class_name()
: der Name der aktuellen Klasse, z. B.Person._class_name() == 'Person'
. Eine Blattklasse – in unserem Beispiel "Person" – kann diese Methode überschreiben, um einen anderen Namen als den Klassennamen bzw. als den im Klassenschlüssel angegebenen Namen zu verwenden. Die Methode kann auch von einer Nicht-Blattklasse überschrieben werden. Beachten Sie in diesem Fall, dass auch deren abgeleitete Klassen die Methode überschreiben sollten. Andernfalls haben alle den gleichen Klassennamen, was schnell zu Irritationen führt._class_key()
: eine Liste von Klassennamen zur Angabe der Hierarchie. Beispiel:Person._class_key() == ['Contact', 'Person']
. Bei tief gestaffelten Hierarchien umfasst die Liste alle Basisklassen zwischenPolyModel
und der aktuellen Klasse. Die aktuelle Klasse gehört dabei zur Liste, PolyModel selbst ist aber nicht enthalten. Dies entspricht dem Wert des Attributsclass_
. Der Name des Datenspeichers lautet "class".
Da der Klassenname im Attribut class_
verwendet wird und dieses Attribut zur Unterscheidung der abgeleiteten Klassen genutzt wird, müssen die von _class_name()
zurückgegebenen Klassennamen in diesen abgeleiteten Klassen eindeutig sein.