Classe PolyModel

A classe PolyModel permite que uma aplicação defina modelos que suportam consultas polimórficas, de uma forma mais flexível do que a classe Model padrão. Uma consulta produzida a partir de uma classe derivada pode ter resultados que são instâncias da classe ou qualquer uma das suas subclasses.PolyModel

Está definido em google.appengine.ext.ndb.polymodel. O exemplo seguinte mostra a flexibilidade oferecida pela 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() devolve instâncias de Person e Company; se Contact for derivado de Model em vez de PolyModel, cada classe teria um kind diferente e Contact.query() não devolveria instâncias de subclasses adequadas de Contact.

Se quiser obter apenas instâncias de Person, use Person.query(). Também pode usar Contact.query(Contact.class_ == 'Person').

Além dos métodos Model normais, o 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 substituir este método para usar um nome diferente como o tipo usado no arquivo 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 no nosso exemplo, pode substituir este 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 substituir este método, mas tenha cuidado: as respetivas subclasses também o devem substituir. Caso contrário, vão usar todas o mesmo nome de classe, e vai ficar muito confuso.
  • _class_key(): uma lista de nomes de classes que indica a hierarquia. Por exemplo, Person._class_key() == ['Contact', 'Person']. Para hierarquias mais profundas, isto inclui todas as bases entre PolyModel e a classe atual, incluindo esta última, mas excluindo o próprio PolyModel. Isto é igual ao valor da propriedade class_. O nome do arquivo de dados é "class".

Uma vez que o nome da classe é usado na propriedade class_ e esta propriedade é usada para distinguir entre as subclasses, os nomes das classes (conforme devolvidos por _class_name()) devem ser exclusivos entre essas subclasses.