A classe PolyModel

Observação: é altamente recomendável a desenvolvedores que criam novos aplicativos usar a biblioteca de cliente NDB, porque ela oferece diversos benefícios em comparação com esta biblioteca de cliente, como armazenamento em cache automático de entidades por meio da API Memcache. Se você estiver usando a antiga biblioteca de cliente DB, leia o Guia de migração de DB para NDB.

A classe PolyModel é a superclasse de definições de modelo de dados que podem ser superclasses de outras definições desse tipo. Uma consulta produzida por uma classe PolyModel pode ter como resultados instâncias da classe ou qualquer uma das subclasses dela.

PolyModel é fornecido pelo módulo google.appengine.ext.db.polymodel.

PolyModel é uma subclasse de Model e herda os métodos de classe e instância dela dessa classe. A classe PolyModel modifica diversos métodos de Model, mas não apresenta novos elementos da interface.

Introdução

Costuma ser útil definir modelos de dados como uma hierarquia de classificação, bem parecida com a maneira como um banco de dados de objetos pode definir uma classe de objetos como uma subclasse de outra. Esse banco de dados pode executar consultas em objetos da classe pai e incluir objetos da subclasse nos resultados. Originalmente, o armazenamento de dados do App Engine não oferece suporte a esse tipo de consulta, mas é possível implementá-lo usando um mecanismo incluído no SDK para Python, a classe PolyModel.

Uma classe de modelo derivada de PolyModel pode ser a classe base de outras classes de modelo. As consultas criadas para essas classes usando os métodos all() e gql() incluem instâncias de subclasses nos resultados.

As subclasses podem definir novas propriedades não presentes em classes pai. No entanto, as subclasses não podem modificar definições de propriedade das classes pai. Se isso acontecer, resultará em um erro DuplicateProperty.

Como referência, aqui está o exemplo simples de entidades e modelos. Observe que a classe PolyModel é fornecida pelo pacote google.appengine.ext.db.polymodel.

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

O polimorfismo não é um recurso nativo do armazenamento de dados. Em vez disso, o polimorfismo é implementado na própria classe PolyModel. Todas as entidades criadas a partir de subclasses PolyModel são armazenadas no Datastore com o mesmo tipo, que é o nome da classe raiz (por exemplo, Animal). Cada objeto armazena sua hierarquia de classes como uma propriedade com vários valores da entidade chamada 'class'. Quando o app cria uma consulta usando os métodos all() ou gql() da classe PolyModel, a consulta acrescenta um filtro na propriedade 'class' que limita os resultados para as entidades criadas a partir da classe ou de quaisquer subclasses.

Como PolyModel usa uma propriedade da entidade para armazenar informações sobre a classe, os índices de consultas polimórficas devem acomodar a propriedade 'class'. O filtro implícito é de igualdade e pode ser combinado com outros filtros de igualdade e desigualdade em outras propriedades.

Observação: PolyModel usa apenas os nomes das classes na propriedade 'class', e não caminhos completos. É possível criar hierarquias de classe com vários nós do mesmo nome, como AB e ACB. Uma consulta feita a um deles retornará entidades dos dois. Da mesma maneira, as consultas de ABC e ACB são funcionalmente idênticas. É melhor evitar criar uma hierarquia de classe única com vários nós do mesmo nome.

PolyModel não aceita a substituição de definições de modelo de propriedade em subclasses. Se uma subclasse tenta redefinir uma propriedade definida em uma superclasse, a definição de classe emite um DuplicatePropertyError.

PolyModel aceita herança múltipla, inclusive herança de várias classes que compartilham uma superclasse (herança "diamante"). Uma classe não pode herdar de duas classes que definem uma definição de modelo de propriedade para a mesma propriedade (isso geraria um DuplicatePropertyError). No entanto, pode herdar de duas classes que herdam a mesma definição de modelo de propriedade da mesma superclasse.

PolyModel não é compatível com propriedades dinâmicas, como o Expando. Não há um equivalente de PolyModel para Expando.

Construtor

O construtor da classe PolyModel é definido assim:

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

Uma classe de modelo que pode ser uma superclasse de outras classes de modelo e com consultas que podem incluir instâncias de subclasses como resultados. Assim como Model, a classe PolyModel precisa ter uma subclasse para definir o tipo das entidades de dados.

A PolyModel é uma subclasse de Model e herda ou modifica os métodos dela.

Argumentos

parent
A instância de Model ou Key da entidade pai da nova entidade.
key_name

O nome da nova entidade. Ele se torna parte da chave primária. Se for None, é usado um ID gerado pelo sistema para a chave.

O valor de key_name não pode começar com um número nem ter o formato __*__. Se o aplicativo usar dados enviados pelo usuário como nomes de chave de entidade do armazenamento de dados (como um endereço de e-mail), o aplicativo precisará limpar o valor primeiro, por exemplo, prefixando-o com uma string conhecida como "key:" para atender a esses requisitos.

Um key_name é armazenado como string Unicode, com os valores de str convertidos em texto ASCII.

**kwds
Valores iniciais das propriedades da instância, como argumentos de palavras-chave. Cada nome corresponde a um atributo da nova instância e precisa corresponder às propriedades fixas definidas na classe PolyModel.

Métodos de classe

Além dos métodos de classe definidos pela classe Model, a classe PolyModel fornece os seguintes métodos de classe:

PolyModel.class_key()

Retorna o nome da classe e o nome de todas as classes pai da classe, como uma tupla.

PolyModel.class_name()

Retorna o nome da classe. Uma classe poderá modificar esse método se o nome da classe Python for alterado, mas as entidades precisam continuar usando o nome da classe original.