PolyModel-Klasse

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 zwischen PolyModel und der aktuellen Klasse. Die aktuelle Klasse gehört dabei zur Liste, PolyModel selbst ist aber nicht enthalten. Dies entspricht dem Wert des Attributs class_. 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.