Classe de modelo NDB

Uma classe herdada da classe Model representa a estrutura de entidades armazenadas no Datastore. Os aplicativos definem classes de modelo para indicar a estrutura das entidades deles e instanciam essas classes de modelo para criar entidades. Todas as classes de modelo precisam herdar (direta ou indiretamente) de Model.

Esta página tem documentação de referência da API. Para uma visão geral, consulte Entidades e chaves do NDB.

Introdução

Uma classe herdada de Model descreve entidades do Datastore.

Todas as classes de modelo precisam herdar (direta ou indiretamente) de Model. As atribuições diretas na definição da classe de modelo podem ser usadas para declarar a estrutura do modelo:

from google.appengine.ext import ndb

class Person(ndb.Model):
  name = ndb.StringProperty()
  age = ndb.IntegerProperty()

Já podemos criar uma entidade Person e gravá-la no Datastore:

p = Person(name='Arthur Dent', age=42)
k = p.put()

O valor retornado de put() é uma Key, que poderá ser usada para recuperar a mesma entidade depois:

p2 = k.get()
p2 == p  # Returns True

Para atualizar uma entidade, basta alterar os atributos dela e regravá-la (isso não altera a chave):

p2.name = 'Arthur Philip Dent'
p2.put()

Também podemos excluir uma entidade usando a chave:

k.delete()

As definições de propriedade no corpo da classe informam ao sistema os nomes e os tipos dos campos a serem armazenados no Datastore, se precisam ser indexados, o valor padrão deles e muito mais. Existem muitos tipos Property diferentes.

O kind normalmente é igual ao nome da classe (exclusivo do nome do módulo ou de qualquer outro escopo pai). Para modificar o tipo (útil para alterações feitas no esquema), defina um método de classe denominado _get_kind() da seguinte forma:

  class MyModel(ndb.Model):
    @classmethod
    def _get_kind(cls):
      return 'AnotherKind'

Um aplicativo não precisará definir duas classes de modelo com o mesmo tipo, mesmo se elas residirem em módulos diferentes. Os tipos de um aplicativo são considerados um "namespace" global.

As subclasses Model podem definir hookspré e pós-chamada para a maioria das operações (get, put, delete, allocate_ids).

Construtor

Um aplicativo normalmente não chama Model(), mas provavelmente chamará o construtor de uma classe que herda de Model. Isso cria uma nova instância desse modelo, também conhecida como entidade.

A entidade recém-criada não é gravada automaticamente no Datastore. Para que isso aconteça, ela precisa ser gravada no Datastore usando-se uma chamada explícita a put().

Argumentos:

As subclasses Model aceitam estes argumentos de palavra-chave:

key
Instância de Key deste modelo. Se o parâmetro key for usado, id e parent precisarão ser None (padrão).
id
ID da chave deste modelo. Se id for usado, a chave precisará ser None (padrão).
parent
Instância de Key do modelo pai ou None de um modelo de nível superior. Se parent for usado, key precisará ser None.
namespace
Namespace para usar nessa entidade ou None (padrão) para usar o namespace atual. Se namespace for usado, key precisará ser None.

Um aplicativo também pode usar o mapeamento de argumentos de palavra-chave para as propriedades do modelo. Por exemplo, o seguinte código funciona:

class Person(ndb.Model):
  name = StringProperty()
  age = IntegerProperty()

p = Person(name='Arthur Dent', age=42)

Não é fácil definir uma propriedade denominada "key", "id", "parent" ou "namespace". Por exemplo, se você passar key="foo" em um construtor ou uma chamada populate(), ele definirá a chave da entidade, não um atributo de propriedade denominado "key".

Observação: se você modificar o construtor em uma subclasse Model, saiba que o construtor também é chamado implicitamente em alguns casos e verifique se há compatibilidade com essas chamadas. Quando uma entidade é lida do Datastore, primeiro uma entidade vazia é criada ao chamar o construtor sem argumentos. Depois, os valores de chave e propriedade são definidos individualmente. Quando get_or_insert() ou get_or_insert_async() cria uma nova instância, passa **construtor_args ao construtor e define a chave posteriormente.

Métodos de classe

allocate_ids(size=None, max=None, parent=None, **ctx_options)

Aloca um intervalo de códigos de chave para esta classe de modelo.

Argumentos

size
Número de IDs a serem alocados. É possível especificar size ou max, mas não ambos.
max
ID máximo a ser alocado. É possível especificar size ou max, mas não ambos.
parent
Chave pai a que os IDs serão alocados.
**ctx_options
Opções de contexto

Retorna uma tupla com (start, end) do intervalo alocado, inclusive.

Um aplicativo não pode chamar allocate_ids() em uma transação.

allocate_ids_async(size=None, max=None, parent=None, **ctx_options)

Versão assíncrona de allocate_ids.

Retorna um objeto Future com resultado que é uma tupla com (start, end) referente ao intervalo alocado, inclusive.

get_by_id(id, parent=None, app=None, namespace=None, **ctx_options)
Retorna uma entidade por ID. Esta é apenas uma forma abreviada de Key(cls, id).get().

Argumentos

id
O ID de uma string ou chave de inteiro.
parent
Chave pai do modelo a receber (get).
app (keyword arg)
ID do aplicativo. Se não for especificado, receberá dados do app atual.
namespace (keyword arg)
Namespace. Se não especificado, receberá dados do namespace padrão.
**ctx_options
Opções de contexto

Retorna uma instância de modelo ou None, se não encontrar.

get_by_id_async(id, parent=None, app=None, namespace=None, **ctx_options)
Versão assíncrona de get_by_id.

Retorna um objeto Future com resultado que é uma instância de modelo ou None, se não encontrar.

get_or_insert(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)
Recupera, de maneira transacional, uma entidade atual ou cria uma nova.

Argumentos

key_name
Um nome de chave (ou seja, um ID de chave de string) a ser recuperado ou criado.
parent
Chave de entidade pai, se houver.
app
ID do aplicativo. Se não for especificado, receberá dados do app atual.
namespace
Namespace. Se não especificado, receberá dados do namespace padrão.
context_options
Opções de contexto

Esta função também utiliza argumentos de palavra-chave a serem passados ao construtor da classe de modelo, caso ainda não exista uma instância referente ao nome de chave especificado. Se já existir uma instância com o key_name e o pai fornecidos, esses argumentos serão descartados.

Retorna uma instância atual da classe Model com o nome de chave e o pai especificados ou uma nova recém-criada.

Esta função usa uma transação. Se o código que chama esta função já estiver em uma transação, ela tentará reutilizar a transação existente. Se o grupo de entidades desta função for incompatível com a transação existente, poderá causar erro.

get_or_insert_async(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)

Esta é a versão assíncrona de get_or_insert.

Ela retorna um objeto Future com resultado que é uma instância atual da classe Model com o nome de chave e o pai especificados ou uma nova recém-criada.

query([filter1, filter2, ...,] ancestor=None, app=None, namespace=None, filters=None, orders=None, default_options=None, projection=None distinct=False group_by=None)

Cria um objeto Query para essa classe, conforme descrito em Consultas.

O argumento de palavra-chave distinct é a forma abreviada de group_by = projection. Todos os outros argumentos de palavra-chave são passados ao construtor Query.

Se forem fornecidos, os argumentos posicionais serão usados para configurar filtros iniciais.

Retorna um objeto Query.

Métodos de instância

populate(**constructor_options)

Define valores das propriedades da entidade. Os argumentos de palavra-chave reconhecem automaticamente nomes de propriedade da mesma maneira que o construtor.

put(**ctx_options)

Grava os dados da entidade no Datastore. Retorna a chave da entidade.

Argumentos

**ctx_options
Opções de contexto
put_async(**ctx_options)

Grava de maneira assíncrona os dados da entidade no Datastore. Retorna um objeto Future. O resultado do objeto Future será o Key da entidade.

Argumentos

**ctx_options
Opções de contexto
to_dict(include=all, exclude=None)

Retorna um dict que contém os valores de propriedade do modelo. Os valores de propriedade de StructuredProperty e LocalStructuredProperty são convertidos recursivamente em dicionários.

Argumentos:

include
Lista opcional de propriedades a serem incluídas. Padrão: tudo.
exclude
Lista opcional de propriedades a serem excluídas. Se houver sobreposição entre include e exclude, exclude "vencerá".

Observação: se o valor de uma propriedade for um objeto mutável (por exemplo, uma lista que representa uma propriedade repetida ou um dict ou list armazenado em um JsonProperty), exceto se o valor for explicitamente convertido (por exemplo, no caso de um StructuredProperty), o mesmo objeto será retornado no dict armazenado na entidade. Nesses casos, mudar o dicionário mudará a entidade e vice-versa.

Dados da instância

key
Propriedade especial para armazenar a chave Model.

Métodos Hook

A subclasse Model de um aplicativo pode definir um ou mais desses métodos como métodos "hook" pré ou pós-operação. Por exemplo, para executar um código antes de cada "get", defina o método _pre_get_hook() da subclasse do modelo. Para conselhos sobre como escrever funções hook, consulte Hooks de modelo.

@classmethod
_pre_allocate_ids_hook(cls, size, max, parent)
Hook executado antes de allocate_ids()
@classmethod
_post_allocate_ids_hook(cls, size, max, parent, future)
Hook executado depois de allocate_ids()
@classmethod
_pre_delete_hook(cls, key)
Hook executado antes de delete()
@classmethod
_post_delete_hook(cls, key, future)
Hook executado depois de delete()
@classmethod
_pre_get_hook(cls, key)
Hook executado antes de Key.get() durante a recuperação de uma entidade deste modelo.
@classmethod
_post_get_hook(cls, key, future)
Hook executado depois de Key.get() durante a recuperação de uma entidade deste modelo.
_pre_put_hook(self)
Hook executado antes de put()
_post_put_hook(self, future)
Hook executado depois de put()

Introspecção

Você pode usar esses métodos para inspecionar as propriedades e a configuração de um determinado modelo. Isso será útil se você estiver escrevendo uma biblioteca ou uma função que aceite vários tipos de modelos.

Pesquisa por tipo

Cada modelo tem um tipo que costuma ser igual ao nome da classe, a menos que seja modificado. Use o tipo para encontrar a classe de modelo associada usando _lookup_model.

class Animal(ndb.Model):
    type = ndb.StringProperty()

print Animal._get_kind()  # 'Animal'
print ndb.Model._lookup_model('Animal')  # class Animal

Observe que _lookup_model só funciona em classes de modelo já importadas pelo aplicativo.

Propriedades

É possível conseguir uma lista de todas as propriedades associadas a um modelo usando _properties.

class User(ndb.Model):
    name = ndb.StringProperty()
    email = ndb.StringProperty()

print User._properties
# {'email': StringProperty('email'), 'name': StringProperty('name')}

_properties também funciona com instâncias Expando.

class Example(ndb.Expando):
  pass

e = Example()
e.foo = 1
e.bar = 'blah'
e.tags = ['exp', 'and', 'oh']
print e._properties
# {'foo': GenericProperty('foo'), 'bar': GenericProperty('bar'),
# 'tags': GenericProperty('tags', repeated=True)}

As instâncias de propriedade podem ser introspectivas. As opções fornecidas ao construtor estão disponíveis como propriedades com o prefixo _.

print User._properties['email']._name  # 'email'
print User._properties['email']._required  # False
print User._properties['email']._default  # None
print User._properties['email']._choices  # None
print User._properties['email']._compressed  # False
print User._properties['email']._indexed  # True
print User._properties['email']._compressed  # False
print User._properties['email']._repeated  # False
print User._properties['email']._verbose_name  # None
print isinstance(User._properties['email'], ndb.StringProperty)  # True

Aliases de método

Cada método na classe Model tem um alias com o prefixo _. Por exemplo, _put() é equivalente a put(). Isso significa que é possível ter propriedades com nomes em conflito com nomes de método, desde que você use sempre os métodos com o prefixo _. No entanto, não é possível especificar propriedades com os nomes key, parent ou id no construtor.

class MyModel(ndb.Model):
    put = ndb.StringProperty()
    query = ndb.StringProperty()
    key = ndb.StringProperty()

entity = MyModel()
entity.put = '1'
entity.query = '2'
entity.key = '3'

entity._put()
print entity
# MyModel(key=Key('MyModel', ...), put=u'1', query=u'2', key=u'3')

print MyModel._query().fetch()
# same as above.

Para criar bibliotecas de terceiros que interagem com modelos arbitrários, recomendamos usar os métodos com prefixo _.