Como criar e usar chaves de entidade

Cada entidade é identificada por uma chave que é exclusiva na instância do Datastore do aplicativo e consiste no seguinte:

  • kind. O tipo é normalmente o nome da classe de modelo à qual a entidade pertence, mas é possível alterar isso para alguma outra string substituindo o classmethod _get_kind().
  • identifier. Você especifica seu próprio nome da chave como o identificador ou permite que o Datastore gere automaticamente um código numérico inteiro.

Como especificar seu próprio nome de chave

O exemplo a seguir cria implicitamente uma chave com um identificador de string usando o parâmetro nomeado id:

account = Account(
    username='Sandy', userid=1234, email='sandy@example.com',
    id='sandy@example.com')

return account.key.id()  # returns 'sandy@example.com'

Como alternativa, você pode definir o nome da chave diretamente:

account.key = ndb.Key('Account', 'sandy@example.com')

# You can also use the model class object itself, rather than its name,
# to specify the entity's kind:
account.key = ndb.Key(Account, 'sandy@example.com')

Como permitir que o Datastore gere um código para usar como chave

Este código mostra como usar um código gerado automaticamente como a chave:

# note: no id kwarg
account = Account(username='Sandy', userid=1234, email='sandy@example.com')
account.put()
# account.key will now have a key of the form: ndb.Key(Account, 71321839)
# where the value 71321839 was generated by Datastore for us.

Como usar o caminho do ancestral na chave

A sequência de entidades começando com uma entidade raiz e prosseguindo de pai para filho, levando a uma determinada entidade, constitui o caminho do ancestral dessa entidade. Uma entidade, o pai dela, o pai do pai dela e assim sucessivamente são os ancestrais dela. As entidades no Datastore formam um espaço de chave hierárquico semelhante à estrutura hierárquica de diretórios de um sistema de arquivos.

A chave completa que identifica a entidade consiste em uma sequência de pares de identificadores de tipo especificando seu caminho de ancestral e terminando com os da própria entidade. O método construtor da classe Key aceita uma sequência de tipos e identificadores e retorna um objeto que representa a chave da entidade correspondente.

O exemplo a seguir mostra um serviço de blog que armazena mensagens por revisão. As mensagens são organizadas em contas e as revisões estão em mensagens.

class Revision(ndb.Model):
    message_text = ndb.StringProperty()
...
ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '1')
ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '2')
ndb.Key('Account', 'larry@example.com', 'Message', 456, 'Revision', '1')
ndb.Key('Account', 'larry@example.com', 'Message', 789, 'Revision', '2')

Na amostra, ('Account', 'sandy@example.com'), ('Message', 123) e ('Revision', '1') são exemplos de pares de identificador de tipo.

Observe que Message não é uma classe de modelo; ele é usado apenas como uma forma de agrupar revisões, não de armazenar dados.

Conforme mostrado no código de amostra, o tipo de entidade é designado pelo último par de nome de tipo na lista: ndb.Key('Revision', '1').

Como usar parâmetros nomeados

Use o parâmetro nomeado parent para designar qualquer entidade diretamente no caminho do ancestral. Todas as notações a seguir representam a mesma chave:

ndb.Key('Account', 'sandy@example.com', 'Message', 123, 'Revision', '1')

ndb.Key('Revision', '1', parent=ndb.Key(
    'Account', 'sandy@example.com', 'Message', 123))

ndb.Key('Revision', '1', parent=ndb.Key(
    'Message', 123, parent=ndb.Key('Account', 'sandy@example.com')))

Como especificar uma entidade raiz

Para uma entidade raiz, o caminho do ancestral está vazio, e a chave consiste unicamente no próprio tipo e identificador da entidade.

sandy_key = ndb.Key(Account, 'sandy@example.com')

Como especificar uma entidade com ancestrais

Para inserir uma nova mensagem com as chaves pai

account_key = ndb.Key(Account, 'sandy@example.com')

# Ask Datastore to allocate an ID.
new_id = ndb.Model.allocate_ids(size=1, parent=account_key)[0]

# Datastore returns us an integer ID that we can use to create the message
# key
message_key = ndb.Key('Message', new_id, parent=account_key)

# Now we can put the message into Datastore
initial_revision = Revision(
    message_text='Hello', id='1', parent=message_key)
initial_revision.put()

Para chaves que foram criadas com um pai, o método parent() retorna uma chave que representa a entidade pai:

message_key = initial_revision.key.parent()

Como usar códigos de chave numérica

É possível criar uma entidade sem especificar um código. Nesse caso, o armazenamento de dados gera automaticamente um código numérico. Se você optar por especificar alguns códigos e permitir que o Datastore gere automaticamente alguns códigos, será possível violar o requisito de chaves exclusivas. Para evitar isso, reserve um intervalo de números a ser usado para escolher códigos ou usar códigos de string para evitar esse problema completamente.

Para reservar um intervalo de códigos, use o método de classe allocate_ids() da classe de modelo:

  • para alocar um número especificado de códigos;
  • para alocar todos os códigos até um determinado valor máximo.

Como alocar códigos

Para alocar 100 códigos para uma determinada classe de modelo MyModel:

first, last = MyModel.allocate_ids(100)

Para alocar 100 códigos para entidades com a chave pai p:

first, last = MyModel.allocate_ids(100, parent=p)

Os valores retornados, first e last, são o primeiro e o último código (inclusive) alocados. Você pode usá-los para criar as chaves da seguinte maneira:

keys = [ndb.Key(MyModel, id) for id in range(first, last+1)]

É garantido que essas chaves não foram retornadas anteriormente pelo gerador de código interno do armazenamento de dados, nem serão retornadas por chamadas futuras para o gerador de código interno. No entanto, o método allocate_ids() não verifica se os códigos retornados estão presentes no armazenamento de dados; ele só interage com o gerador de códigos.

Para alocar todos os códigos até um determinado valor máximo:

first, last = MyModel.allocate_ids(max=N)

Neste formulário, todos os códigos menores ou iguais a N são considerados alocados. Os valores de retorno, first e last, indicam o intervalo de códigos reservados por esta operação. Não é um erro tentar reservar códigos já alocados. Se isso acontecer, first indica o primeiro código ainda não alocado e last é o último código alocado.