Clase PolyModel

La clase PolyModel permite que una aplicación defina modelos que admitan consultas polimórficas de una forma más flexible que la clase Model estándar. Una consulta generada a partir de una clase derivada de PolyModel puede tener resultados que sean instancias de la clase o de cualquiera de sus subclases.

Se define en google.appengine.ext.ndb.polymodel. En el siguiente ejemplo se muestra la flexibilidad que ofrece la clase 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() devuelve Person y Company instancias; si Contact se deriva de Model en lugar de PolyModel, cada clase tendría un kind diferente y Contact.query() no devolvería instancias de subclases adecuadas de Contact.

Si solo quieres obtener instancias de Person, usa Person.query(). También puedes usar Contact.query(Contact.class_ == 'Person').

Además de los métodos de Model habituales, PolyModel tiene algunos métodos de clase interesantes:

  • _get_kind(): el nombre de la clase raíz (por ejemplo, Person._get_kind() == 'Contact'). La clase raíz, Contact en este ejemplo, puede anular este método para usar otro nombre como el tipo usado en el almacén de datos (para toda la jerarquía que tiene su raíz aquí).
  • _class_name(): el nombre de la clase actual (por ejemplo, Person._class_name() == 'Person'). Una clase hoja, como Person en nuestro ejemplo, puede anular este método para usar un nombre diferente como nombre de clase y en la clave de clase. Una clase que no sea hoja también puede anular este método, pero ten cuidado: sus subclases también deben anularlo, ya que, de lo contrario, todas usarán el mismo nombre de clase y te confundirás.
  • _class_key(): una lista de nombres de clase que indica la jerarquía. Por ejemplo, Person._class_key() == ['Contact', 'Person']. En el caso de las jerarquías más profundas, se incluirán todas las bases entre PolyModel y la clase actual, incluida esta última, pero excluyendo PolyModel. Es el mismo valor que el de la propiedad class_. Su nombre de almacén de datos es "class".

Como el nombre de la clase se usa en la propiedad class_ y esta propiedad se usa para distinguir entre las subclases, los nombres de las clases (tal como los devuelve _class_name()) deben ser únicos entre esas subclases.