A classe PolyModel

Nota: os programadores que criam novas aplicações são fortemente aconselhados a usar a biblioteca de cliente NDB, que tem várias vantagens em comparação com esta biblioteca de cliente, como o armazenamento em cache automático de entidades através da API Memcache. Se estiver a usar atualmente a biblioteca cliente DB mais antiga, leia o guia de migração de DB para NDB

A classe PolyModel é a superclasse para definições de modelos de dados que podem ser superclasses para outras definições de modelos de dados. Uma consulta produzida a partir de uma classe PolyModel pode ter resultados que são instâncias da classe ou de qualquer uma das respetivas subclasses.

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

PolyModel é uma subclasse de Model e herda os respetivos métodos de classe e de instância dessa classe. A classe PolyModel substitui vários métodos de Model, mas não introduz novos elementos de interface.

Introdução

Muitas vezes, é útil definir modelos de dados como uma hierarquia de classificação, tal como uma base de dados de objetos pode definir uma classe de objetos como uma subclasse de outra. Uma base de dados deste tipo pode executar consultas em objetos da classe principal e incluir objetos da subclasse nos resultados. O armazenamento de dados do App Engine não suporta este tipo de consulta de forma nativa, mas pode implementá-lo através de um mecanismo incluído no Python SDK, a classe PolyModel.

Uma classe de modelo derivada de PolyModel pode ser a classe base para outras classes de modelo. As consultas criadas para estas classes através dos métodos all() e gql() sabem incluir instâncias de subclasses nos resultados.

As subclasses podem definir novas propriedades não presentes nas classes principais. No entanto, as subclasses não podem substituir as definições de propriedades das classes principais. (Se o fizer, ocorre um erro DuplicateProperty.)

Para referência, aqui está o exemplo simples de Entidades e modelos. Repare 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 é uma funcionalidade nativa do arquivo 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 arquivo de dados com o mesmo tipo, que é o nome da classe raiz (por exemplo, Animal). Cada objeto armazena a respetiva hierarquia de classes como uma propriedade de vários valores da entidade denominada 'class'. Quando a app cria uma consulta através do método all() ou gql() de uma classe PolyModel, a consulta inclui um filtro na propriedade 'class' que limita os resultados a entidades criadas a partir da classe ou de qualquer subclasse.

Uma vez que o PolyModel usa uma propriedade da entidade para armazenar informações de classe, os índices para consultas polimórficas têm de acomodar a propriedade 'class'. O filtro implícito é um filtro de igualdade e pode ser combinado com outros filtros de igualdade e filtros de desigualdade noutras propriedades.

Nota: o PolyModel usa apenas os nomes das classes na propriedade 'class' e não os caminhos completos. É possível criar hierarquias de classes com vários nós do mesmo nome, como AB e ACB. Uma consulta de um devolve entidades de ambos. Da mesma forma, as consultas para ABC e ACB são funcionalmente idênticas. É aconselhável evitar criar uma única hierarquia de classes com vários nós com o mesmo nome.

O PolyModel não suporta a substituição de definições de modelos de propriedades em subclasses. Se uma subclasse tentar redefinir uma propriedade definida numa superclasse, a definição da classe gera um DuplicatePropertyError.

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

O PolyModel não suporta propriedades dinâmicas, ao contrário do Expando. Não existe um equivalente de PolyModel para Expando.

Construtor

O construtor da classe PolyModel é definido da seguinte forma:

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

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

PolyModel é uma subclasse de Model e herda ou substitui os respetivos métodos.

Argumentos

parent
A instância do modelo ou a instância da chave para a entidade que é a principal da nova entidade.
key_name

O nome da nova entidade. O nome passa a fazer parte da chave principal. Se None, é usado um ID gerado pelo sistema para a chave.

O valor de key_name não pode começar por um número e não pode ter o formato __*__. Se a sua aplicação usar dados enviados pelo utilizador como nomes de chaves de entidades da base de dados (como um endereço de email), a aplicação deve limpar primeiro o valor, por exemplo, prefixando-o com uma string conhecida como "key:", para cumprir estes requisitos.

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

**kwds
Valores iniciais para as propriedades da instância, como argumentos de palavras-chave. Cada nome corresponde a um atributo da nova instância e tem de corresponder a 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()

Devolve o nome da classe e os nomes de todas as classes principais da classe, como uma tupla.

PolyModel.class_name()

Devolve o nome da classe. Uma classe pode substituir este método se o nome da classe Python for alterado, mas as entidades devem continuar a usar o nome da classe original.