Clase Model de NDB

Una clase que se hereda de la clase Model representa la estructura de las entidades almacenadas en Datastore. Las aplicaciones definen las clases de modelo para indicar la estructura de sus entidades y, luego, crean instancias de esas clases de modelo a fin de formar entidades. Todas las clases de modelo se deben heredar (directa o indirectamente) de Model.

Esta página tiene documentación de referencia de API. Para obtener una descripción general, consulta Claves y entidades de NDB.

Introducción

Una clase que se hereda de Model describe las entidades de Datastore.

Todas las clases de modelo se deben heredar (directa o indirectamente) de Model. Se pueden usar asignaciones sencillas en la definición de la clase de modelo para declarar la estructura del modelo:

from google.appengine.ext import ndb

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

Ahora podemos crear una entidad Person y escribirla en Datastore:

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

El valor que se muestra de put() es una clave, que se puede usar para recuperar la misma entidad más adelante:

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

Para actualizar una entidad, solo debes cambiar sus atributos y volver a escribirla (ten en cuenta que esto no cambia la clave):

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

También se puede borrar una entidad (mediante la clave):

k.delete()

Las definiciones de propiedad en el cuerpo de la clase le indican al sistema los nombres y los tipos de los campos que se almacenarán en Datastore, así como si se deben indexar, su valor predeterminado y más. Existen muchos Tipos de propiedad.

En general, la categoría es la misma que el nombre de la clase (exclusivo del nombre del módulo o cualquier alcance superior). A fin de anular la categoría (útil para los cambios de esquema), define un método de clase denominado _get_kind(), de la manera siguiente:

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

Una aplicación no debe definir dos clases de modelo con la misma categoría, incluso si se alojan en módulos diferentes. Las categorías de una aplicación se consideran “espacio de nombres” global.

Las subclases de Model pueden definir hooks previos y posteriores a la llamada en la mayoría de las operaciones (get, put, delete y allocate_ids).

Constructor

Por lo general, una aplicación no llamará a Model(), pero es probable que llame al constructor de una clase que se hereda de Model. Esto crea una instancia nueva para este modelo, también conocida como entidad.

La entidad recién creada no se escribe de forma automática en Datastore. Para que esto suceda, se debe escribir en Datastore mediante una llamada explícita a put().

Argumentos:

Las subclases Model admiten los siguientes argumentos de palabras clave:

key
La instancia clave para este modelo. Si se usa el parámetro key, id y parent deben ser None (el valor predeterminado).
id
El ID de clave para este modelo. Si se usa id, la clave debe ser None (el valor predeterminado).
parent
La instancia clave para el modelo superior o None si se trata de uno de nivel superior. Si se usa parent, key debe ser None.
namespace
El espacio de nombres que se debe usar en esta entidad o None (valor predeterminado) para usar el espacio de nombres actual. Si se usa namespace, key debe ser None.

Una aplicación también puede usar argumentos de palabras clave mapeados a las propiedades del modelo. Por ejemplo, lo siguiente funciona:

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

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

No puedes definir con facilidad una propiedad denominada “key”, “id”, “parent” o “namespace”. Por ejemplo, si pasas key="foo" en un constructor o realizas una llamada a populate(), se establece la clave de la entidad y no un atributo de propiedad llamado “key”.

Nota: Si anulas el constructor en una subclase Model, ten en cuenta que, en algunos casos, también se llama al constructor de manera implícita, y asegúrate de que admites esas llamadas. Cuando se lee una entidad en Datastore, primero se crea una entidad vacía mediante una llamada al constructor sin argumentos y, después, los valores de clave y propiedad se configuran uno por uno. Cuando get_or_insert() o get_or_insert_async() crean una instancia nueva, se pasa **constructor_args al constructor y, luego, se establece la clave.

Métodos de clase

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

Asigna un rango de ID de clave para esta clase de modelo.

Argumentos

size
Cantidad de ID que se asignarán. Se pueden especificar size o max, pero no ambos.
max
ID máximo que se asignará. Se pueden especificar size o max, pero no ambos.
parent
Clave superior para la que se asignarán los ID.
**ctx_options
Opciones de contexto

Muestra una tupla con (inicio, fin) inclusiva para el rango asignado.

Una aplicación no puede llamar a allocate_ids() en una transacción.

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

Versión asíncrona de allocate_ids.

Muestra un objeto Future cuyo resultado es una tupla con (inicio, fin) para el rango asignado, inclusive.

get_by_id(id, parent=None, app=None, namespace=None, **ctx_options)
Muestra una entidad por ID. Esta marca es solo una forma abreviada de Key(cls, id).get().

Argumentos

id
Un ID de clave de string o número entero.
parent
La clave superior del modelo que se obtendrá.
app (argumento de palabra clave)
El ID de la app. Si no se especifica, obtiene los datos de la app actual.
namespace (argumento de palabra clave)
Espacio de nombres. Si no se especifica, obtiene datos para el espacio de nombres predeterminado.
**ctx_options
Opciones de contexto

Muestra una instancia de modelo o None si no se encuentra una.

get_by_id_async(id, parent=None, app=None, namespace=None, **ctx_options)
Versión asíncrona de get_by_id.

Muestra un objeto Future cuyo resultado es una instancia de modelo o None si no se encuentra una.

get_or_insert(key_name, parent=None, app=None, namespace=None, context_options=None, **constructor_args)
Recupera mediante una transacción una entidad existente o crea una nueva.

Argumentos

key_name
Un nombre de clave (es decir, un ID de clave de string) que se recuperará o creará.
parent
Clave de entidad principal, si existe.
app
El ID de la app. Si no se especifica, obtiene los datos de la app actual.
namespace
Espacio de nombres. Si no se especifica, obtiene datos para el espacio de nombres predeterminado.
context_options
Opciones de contexto

Esta función también usa argumentos de palabras clave a fin de pasar al constructor de la clase de modelo si no existe una instancia para el nombre de clave especificado. Si ya existe una instancia con el key_name y el superior proporcionado, se descartarán estos argumentos.

Muestra la instancia existente de la clase Model con el nombre de clave y el superior especificados o una nueva que se acaba de crear.

Esta función usa una transacción. Si el código que llama a esta función ya está en una transacción, la función intenta usar de nuevo la transacción existente. Puede haber un error si el grupo de entidad de esta función no es compatible con la transacción existente.

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

Esta es la versión asíncrona de get_or_insert.

Muestra un objeto Future cuyo resultado es una instancia existente de la clase Model con el nombre de clave y el superior especificados o una nueva que se acaba de crear.

query([filter1, filter2, ...,] ancestor=None,app=None,namespace=None,filters=None,orders=None,default_options=None,projection=Nonedistinct=Falsegroup_by=None)

Crea un objeto Query para esta clase como se describe en Consultas.

El argumento de palabra clave distinct es la abreviatura de group_by = projection. Los demás argumentos de palabras clave se pasan al Constructor de consultas.

Si se proporcionan argumentos de posición, se usan para configurar los filtros iniciales.

Muestra un objeto Query.

Métodos de instancia

populate(**constructor_options)

Configura valores de las propiedades de entidad. Sus argumentos de palabras clave reconocen automáticamente los nombres de la propiedad de la misma manera que lo hace el constructor.

put(**ctx_options)

Escribe los datos de la entidad en Datastore. Muestra la Clave de la entidad.

Argumentos

**ctx_options
Opciones de contexto
put_async(**ctx_options)

Escribe de manera asíncrona los datos de la entidad en Datastore. Muestra un objeto Future. El resultado del objeto Future será la clave de la entidad.

Argumentos

**ctx_options
Opciones de contexto
to_dict(include=all, exclude=None)

Muestra un dict que contiene los valores de propiedad del modelo. Los valores de propiedad de StructuredProperty y LocalStructuredProperty se convierten en diccionarios de manera recurrente.

Argumentos:

include
Lista opcional de las propiedades que se incluirán. Predeterminado: todas.
exclude
Lista opcional de las propiedades que se excluirán. Si include y exclude se superponen, entonces, exclude “toma precedencia”.

Nota: Si el valor de una propiedad es un objeto mutable (p. ej., una lista que represente una propiedad repetida o un diccionario o lista almacenados en una JsonProperty), se muestra el mismo objeto en el diccionario que está almacenado en la entidad, a menos que el valor se convierta de forma explícita (p. ej., en el caso de una StructuredProperty). En tales casos, si cambias el diccionario, cambiará la entidad y viceversa.

Datos de instancia

key
Propiedad especial para almacenar la clave Model.

Métodos de hook

La subclase de Model de una aplicación puede definir uno o más de estos métodos como métodos de “hook” previos y posteriores a la operación. P. ej., para ejecutar algún código antes de cada “get”, define el método _pre_get_hook() de la subclase de modelo. Si deseas recibir asesoramiento para escribir funciones de hook, consulta Hooks de modelo.

@classmethod
_pre_allocate_ids_hook(cls, size, max, parent)
Un hook que se ejecuta antes que allocate_ids()
@classmethod
_post_allocate_ids_hook(cls, size, max, parent, future)
Un hook que se ejecuta después que allocate_ids()
@classmethod
_pre_delete_hook(cls, key)
Un hook que se ejecuta antes que delete()
@classmethod
_post_delete_hook(cls, key, future)
Un hook que se ejecuta después que delete()
@classmethod
_pre_get_hook(cls, key)
Un hook que se ejecuta antes que Key.get() cuando se obtiene una entidad de este modelo.
@classmethod
_post_get_hook(cls, key, future)
Un hook que se ejecuta después que Key.get() cuando se obtiene una entidad de este modelo.
_pre_put_hook(self)
Un hook que se ejecuta antes que put()
_post_put_hook(self, future)
Un hook que se ejecuta después que put()

Introspección

Puedes usar estos métodos para inspeccionar las propiedades y la configuración de un modelo especificado. Esto es útil si escribes una biblioteca o función que acepta varios tipos de modelos.

Cómo buscar por categoría

Cada modelo tiene una categoría que suele ser la misma que el nombre de la clase, a menos que se haya anulado. Puedes usar la categoría para buscar la clase de modelo asociada mediante _lookup_model.

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

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

Ten en cuenta que _lookup_model solo funciona para las clases de modelo que la aplicación ya importó.

Propiedades

Puedes obtener una lista de todas las propiedades asociadas con un modelo mediante _properties.

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

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

_properties también funciona para instancias de 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)}

Se puede hacer una introspección de las instancias de propiedad. Las opciones que se proporcionan al constructor están disponibles como propiedades con el prefijo _.

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

Alias de método

Cada método en la clase Model tiene un alias con el prefijo _. Por ejemplo, _put() es equivalente a put(). Esto significa que puedes tener propiedades con nombres que entran en conflicto con los nombres de métodos, siempre y cuando uses los métodos con el prefijo _. Sin embargo, ten en cuenta que no puedes especificar propiedades denominadas key, parent o id en el constructor.

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.

Es recomendable usar los métodos con el prefijo _ si creas bibliotecas de terceros que interactúen con modelos arbitrarios.