La clase PolyModel

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

Se define en google.appengine.ext.ndb.polymodel. El ejemplo siguiente muestra la flexibilidad proporcionada por 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() muestra las instancias de Person y Company; si Contact derivara de Model en lugar de PolyModel, cada clase tendría un kind diferente y Contact.query() no mostraría instancias de subclases apropiadas de Contact.

Si deseas recuperar solo instancias Person, usa Person.query(). También puedes usar Contact.query(Contact.class_ == 'Person').

Además de los métodos normales de la clase Model, PolyModel posee algunos métodos de clase interesantes:

  • _get_kind(): el nombre de la clase raíz, como Person._get_kind() == 'Contact'. La clase raíz, Contact en este ejemplo, puede anular este método para usar un nombre diferente como el tipo usado en el almacén de datos (para toda la jerarquía cuya raíz está aquí).
  • _class_name(): es el nombre de la clase actual, como Person._class_name() == 'Person'. Una clase hoja, Person en nuestro ejemplo, puede anular este método para usar un nombre diferente como el nombre de clase y en la clave de clase. Una clase hoja diferente también puede anular este método, pero ten en cuenta lo siguiente: sus subclases también deberían anularlo o, de lo contrario, todas usarán el mismo nombre de clase, y pronto te confundirás mucho.
  • _class_key(): es una lista de nombres de clase que proporcionan la jerarquía. Por ejemplo, Person._class_key() == ['Contact', 'Person']. Para jerarquías más profundas, esto incluirá todas las bases entre PolyModel y la clase actual, incluida esta última, pero sin incluir la clase PolyModel. Es igual al valor de la propiedad class_. Su nombre de almacén de datos es 'class'.

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