Classe PolyModel

A classe PolyModel possibilita que um aplicativo defina modelos compatíveis com consultas polimórficas com mais flexibilidade que a classe Model padrão. Uma consulta produzida por uma classe derivada de PolyModel pode ter como resultados instâncias da classe ou de qualquer das subclasses dela.

Está definida em google.appengine.ext.ndb.polymodel. O exemplo a seguir mostra a flexibilidade da classe 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() retorna instâncias Person e Company. Se Contact fosse derivado de Model em vez de PolyModel, cada classe teria um kind diferente e Contact.query() retornaria instâncias de subclasses apropriadas de Contact.

Caso você queira recuperar apenas instâncias Person, use Person.query(). Também é possível usar o Contact.query(Contact.class_ == 'Person').

Além dos métodos regulares Model, PolyModel tem alguns métodos de classe interessantes:

  • _get_kind(): o nome da classe raiz. Por exemplo, Person._get_kind() == 'Contact'. A classe raiz, Contact neste exemplo, pode modificar esse método para usar um nome diferente como o tipo usado no armazenamento de dados (para toda a hierarquia enraizada aqui).
  • _class_name(): o nome da classe atual. Por exemplo, Person._class_name() == 'Person'. Uma classe folha, Person neste exemplo, pode modificar esse método para usar um nome diferente como o nome da classe e na chave da classe. Uma classe não folha também pode modificar este método, mas cuidado: as subclasses também precisam substituí-la, ou elas usarão o mesmo nome de classe e em breve você ficará muito confuso.
  • _class_key(): uma lista de nomes de classe que dão a hierarquia. Por exemplo, Person._class_key() == ['Contact', 'Person']. Para hierarquias mais profundas, isso incluirá todas as bases entre PolyModel e a classe atual, inclusive esta última, mas exceto a própria PolyModel. Este é o mesmo valor da propriedade class_. O nome do armazenamento de dados é "class".

Como o nome da classe é usado na propriedade class_ e essa propriedade é usada para distinguir entre as subclasses, os nomes das classes (conforme retornado por _class_name()) precisam ser exclusivos entre essas subclasses.