Die PolyModel-Klasse

Hinweis: Entwicklern von neuen Anwendungen wird dringend empfohlen, die NDB-Clientbibliothek zu verwenden. Diese bietet im Vergleich zur vorliegenden Clientbibliothek verschiedene Vorteile, z. B. das automatische Caching von Entitäten über die Memcache API. Wenn Sie derzeit die ältere DB-Clientbibliothek verwenden, finden Sie weitere Informationen im Leitfaden zur Migration von DB- zu NDB-Clientbibliotheken.

Die PolyModel-Klasse ist die übergeordnete Klasse für Datenmodelldefinitionen, die wiederum übergeordnete Klassen für andere Datenmodelldefinitionen sein können. Eine über eine PolyModel-Klasse erstellte Anfrage kann zu Ergebnissen führen, die Instanzen der Klasse oder ihrer Unterklassen sind.

PolyModel wird vom Modul google.appengine.ext.db.polymodel bereitgestellt.

PolyModel ist eine Unterklasse von Model und erbt die Klassen- und Instanzmethoden dieser Klasse. Mit der PolyModel-Klasse werden einige der Methoden der Klasse Model überschrieben, aber keine neuen Oberflächenelemente eingeführt.

Einführung

Häufig ist es hilfreich, Datenmodelle als Klassifizierungshierarchie zu definieren. Dies ähnelt der Art und Weise, wie mit Objektdatenbanken eine Objektklasse als Unterklasse einer anderen definiert werden kann. Mit so einer Datenbank können Sie Anfragen bei Objekten der übergeordneten Klasse durchführen, wobei in die Ergebnisse Objekte der Unterklasse einbezogen werden können. Nativ wird diese Art Anfrage vom App Engine-Datastore nicht unterstützt. Sie können sie aber mit einem Mechanismus im Python-SDK implementieren. Es ist die Klasse PolyModel.

Eine von PolyModel abgeleitete Modellklasse kann die Basisklasse für andere Modellklassen sein. Abfragen, die für diese Klassen mit den Methoden all() und gql() erstellt wurden, enthalten in den Ergebnissen Instanzen von Unterklassen.

Mit Unterklassen können Sie neue Attribute definieren, die in übergeordneten Klassen nicht vorhanden sind. Mit Unterklassen können Sie allerdings keine Attributdefinitionen von übergeordneten Klassen überschreiben. Dies führt zum Fehler DuplicateProperty.

Als Referenz finden Sie hier ein einfaches Beispiel zu Entitäten und Modellen. Die Klasse PolyModel wird vom Paket google.appengine.ext.db.polymodel bereitgestellt.

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

Nativ weist der Datenspeicher keine Polymorphie auf. Stattdessen wird Polymorphie in der Klasse PolyModel selbst implementiert. Alle Entitäten, die aus PolyModel-Unterklassen erstellt wurden, werden im Datenspeicher desselben Typs gespeichert. Der Name des Datenspeichers ist dann der Name der Stammklasse (beispielsweise Animal). Jedes Objekt speichert seine Klassenhierarchie als mehrwertiges Attribut der Entität 'class'. Wenn die Anwendung eine Abfrage mit den Methoden all() oder gql() einer PolyModel-Klasse erstellt, enthält die Abfrage einen Filter für das Attribut 'class'. Dieses beschränkt Ergebnisse auf Entitäten, die aus der Klasse oder einer Unterklasse erstellt wurden.

Da PolyModel Klasseninformationen in einem Attribut der Entität speichert, müssen Indexe für polymorphe Abfragen das Attribut 'class' enthalten. Der implizierte Filter ist ein Gleichheitsfilter, der mit Gleichheits- und Ungleichheitsfiltern aus anderen Attributen kombiniert werden kann.

Hinweis: PolyModel verwendet im Attribut 'class' nur die Namen der Klassen, aber nicht vollständige Pfade. Sie können auch Klassenhierarchien mit mehreren gleichnamigen Knoten wie A → B und A → C → B erstellen. Mit einer Anfrage für ein Element werden Entitäten für beide zurückgegeben. Ebenso sind Abfragen nach A → B → C und A → C → B funktional identisch. Sie sollten nicht einzelne Klassenhierarchie mit mehreren Knoten und denselben Namen erstellen.

PolyModel unterstützt nicht das Überschreiben von Attributmodelldefinitionen in Unterklassen. Wenn eine Unterklasse versucht, ein Attribut neu zu definieren, das in einer Basisklasse definiert ist, löst die Klassendefinition einen DuplicatePropertyError aus.

PolyModel unterstützt die mehrfache Vererbung, einschließlich des Erbens von mehreren Klassen einer gemeinsamen Basisklasse ("Diamond"-Vererbung). Eine Klasse kann nicht von zwei Klassen erben, die jeweils eine Attributmodelldefinition für dasselbe Attribut definieren (dies würde einen DuplicatePropertyError auslösen). Eine Vererbung von zwei Klassen, die dieselbe Attributmodelldefinition von derselben übergeordneten Klasse erben, ist jedoch möglich.

PolyModel unterstützt keine dynamischen Attribute, wie es bei Expando der Fall ist. Es gibt in Expando keine Entsprechung für PolyModel.

Konstruktor

Der Konstruktor der PolyModel-Klasse ist wie folgt definiert:

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

Eine Modellklasse, bei der es sich um eine übergeordnete Klasse anderer Modellklassen handeln kann, und deren Anfragen Instanzen von Unterklassen als Ergebnisse umfassen können. Wie bei Model müssen für die PolyModel-Klasse abgeleitete Klassen definiert werden, um den Typ der Datenentitäten zu definieren.

PolyModel ist eine abgeleitete Klasse von Model und erbt oder überschreibt vorhandene Methoden.

Argumente

parent
Die Modell- oder Schlüsselinstanz der Entität, die das übergeordnete Element der neuen Entität ist.
key_name

Der Name der neuen Entität. Der Name wird Teil des primären Schlüssels. Falls der Wert None ist, wird für den Schlüssel eine vom System generierte ID verwendet.

Der Wert für key_name darf nicht mit einer Ziffer beginnen und nicht in dieser Form vorliegen: __*__. Wenn Ihre Anwendung vom Nutzer gesendete Daten als Schlüsselnamen für Datenspeicherentitäten verwendet (beispielsweise eine E-Mail-Adresse), sollte die Anwendung zuerst den Wert bereinigen, beispielsweise durch Voranstellen eines bekannten Strings wie "key:", um diese Anforderungen zu erfüllen.

Ein key_name wird als Unicode-String gespeichert, wobei str-Werte in ASCII-Text konvertiert werden.

**kwds
Anfängliche Werte für die Attribute der Instanz als Keyword-Argumente. Jeder Name entspricht einem Attribut der neuen Instanz, der mit festen Properties übereinstimmen muss, die in der PolyModel-Klasse definiert sind.

Klassenmethoden

Zusätzlich zu den von der Model-Klasse definierten Klassenmethoden stellt die PolyModel-Klasse die folgenden Klassenmethoden bereit:

PolyModel.class_key()

Gibt den Namen der Klasse und die Namen aller übergeordneten Klassen der Klasse als Tupel zurück.

PolyModel.class_name()

Gibt den Namen der Klasse zurück. Sie können diese Methode mit Klassen überschreiben, wenn sich der Name der Python-Klasse ändert. Bei den Entitäten hingegen sollten Sie weiterhin den ursprünglichen Klassennamen verwenden.