Referencia de propiedad de la entidad

Cloud Datastore es compatible con diversos tipos de datos para valores de propiedad. Entre estos, se incluyen las siguientes opciones:

  • Números enteros
  • Números de punto flotante
  • Strings
  • Fechas
  • Datos binarios

Para obtener una lista completa de los tipos, consulta Tipos de valores y propiedades.

Tipos de valores y propiedades

Los valores de datos asociados con una entidad constan de una o más propiedades. Cada propiedad posee un nombre y uno o más valores. Una propiedad puede tener valores de más de un tipo, y dos entidades pueden tener valores de diferentes tipos para la misma propiedad. Las propiedades pueden estar indexadas o no (las consultas que ordenan o filtran en una propiedad P ignorarán las entidades en las que P no está indexada). Una entidad puede tener como máximo 20,000 propiedades indexadas.

Se admiten los siguientes tipos de valor:

Cuando una consulta incluye una propiedad con valores de varios tipos, Cloud Datastore usa un orden determinista basado en las representaciones internas:

  1. Valores nulos
  2. números de coma fija
    • enteros
    • fechas y horarios
  3. Valores booleanos
  4. Secuencias de bytes
    • String de Unicode
    • Claves de Blobstore
  5. Números de punto flotante
  6. Claves de Cloud Datastore

Las strings de texto largas y las strings largas no tienen un orden definido porque no están indexadas.

Tipos de propiedad

NDB es compatible con las funciones siguientes:

Tipo de propiedad Descripción
IntegerProperty Número entero de 64 bits con firma.
FloatProperty Número de punto flotante de doble precisión
BooleanProperty Booleano
StringProperty String de Unicode; hasta 1,500 bytes, indexada
TextProperty Strings de Unicode; longitud ilimitada, no indexada
BlobProperty String de bytes no indexada:
si configuras indexed=True, hasta 1,500 bytes, indexada;
si indexed es False (la opción predeterminada), longitud ilimitada, no indexada.
Argumento de palabra clave opcional: compressed.
DateTimeProperty Fecha y hora (consulta Propiedades de fecha y hora)
DateProperty Fecha (consulta Propiedades de fecha y hora)
TimeProperty Hora (consulta Propiedades de fecha y hora)
GeoPtProperty Ubicación geográfica. Esto es un objeto ndb.GeoPt. El objeto tiene atributos lat y lon, ambos con punto flotante. Puedes construir uno con dos puntos flotantes como ndb.GeoPt(52.37, 4.88) o con una string ndb.GeoPt("52.37, 4.88"). (Esta es en realidad la misma clase que db. db.GeoPt)
KeyProperty Clave de Cloud Datastore
Argumento de palabra clave opcional: kind=kind, para que las claves asignadas a esta propiedad siempre tengan el tipo indicado. Puede ser una string o una subclase Model.
BlobKeyProperty Clave de Blobstore
Corresponde a BlobReferenceProperty en la API de db anterior, pero el valor de propiedad es una BlobKey y no BlobInfo; puedes construir un BlobInfo con esto a través de BlobInfo(blobkey)
UserProperty Objeto de usuario.
StructuredProperty Incluye un tipo de modelo dentro de otro, según el valor (consulta Propiedades estructuradas)
LocalStructuredProperty Como StructuredProperty, pero la representación en el disco es un blob opaco y no está indexado (consulta Propiedades estructuradas).
Argumento de palabra clave opcional: compressed.
JsonProperty El valor es un objeto de Python (como una lista, un diccionario o una string) que se puede serializar con el módulo de Python json. Cloud Datastore almacena la serialización de JSON como un blob. Sin indexar de forma predeterminada.
Argumento de palabra clave opcional: compressed.
PickleProperty El valor es un objeto de Python (como una lista, un diccionario o una string) que se puede serializar con el protocolo de serialización de Python. Cloud Datastore almacena la serialización como un blob. Sin indexar de forma predeterminada.
Argumento de palabra clave opcional: compressed.
GenericProperty Valor genérico
Mayormente lo usa la clase Expando, pero también se puede usar de manera explícita. Su tipo puede ser cualquiera de int, long, float, bool, str, unicode, datetime, Key, BlobKey, GeoPt, User, None.
ComputedProperty Valor computado de otras propiedades a partir de una función definida por el usuario. (Consulta Propiedades computadas).

Algunas de estas propiedades tienen un argumento de palabra clave opcional, compressed. Si la propiedad tiene compressed=True, entonces sus datos se comprimen con gzip en el disco. Ocupa menos espacio, pero necesita CPU para codificarse o decodificarse en las operaciones de escritura y lectura.

Tanto la compresión como la descompresión son "lentas"; un valor de propiedad comprimido solo se descomprimirá la primera vez que accedas a él. Si lees una entidad que contiene un valor de propiedad comprimida y lo escribes sin acceder a esa propiedad, no se descomprimirá ni comprimirá en absoluto. La memoria almacenada en caché en contexto participa en este esquema lento también, pero Memcache siempre almacena el valor comprimido para propiedades comprimidas.

Debido al tiempo adicional que la CPU necesita para la compresión, generalmente es mejor usar propiedades comprimidas solo si los datos fueran demasiado grandes para ajustarse sin ellos. Recuerda que la compresión basada en gzip generalmente no es efectiva para imágenes y otros datos de medios, porque esos formatos ya están comprimidos con un algoritmo de compresión específico de medios (p. ej., JPEG para imágenes).

Opciones de propiedad

La mayoría de los tipos de propiedades admiten algunos argumentos estándares. El primero es un argumento de posicionamiento opcional que especifica el nombre de la propiedad de Cloud Datastore. Puedes usar esto para darle a la propiedad un nombre diferente en Cloud Datastore al de la aplicación. Un uso común es reducir el espacio en Cloud Datastore para que use nombres de propiedad abreviados, mientras que tu código usa nombres más largos y significativos. Por ejemplo,

class Employee(ndb.Model):
    full_name = ndb.StringProperty('n')
    retirement_age = ndb.IntegerProperty('r')

Esto es muy útil para propiedades repetidas en las que esperas muchos valores por entidad.

Además, la mayoría de los tipos de propiedad admiten los argumentos de palabras clave siguientes:

Argumento Tipo Valor predeterminado Descripción
indexed bool Generalmente True Incluye la propiedad en los índices de Cloud Datastore; si False, los valores no se pueden consultar, pero las escrituras son más rápidas. No todos los tipos de propiedad admiten la indexación; configurar indexed para True falla en estos casos.
Las propiedades no indexadas toman menos operaciones de escritura que las propiedades indexadas.
repeated bool False El valor de propiedad es una lista de Python que contiene valores del tipo subyacente (consulta Propiedades repetidas).
No se puede combinar con required=True o default=True.
required bool False La propiedad debe tener un valor especificado.
default Tipo subyacente de la propiedad Ninguno Valor predeterminado de la propiedad si no se especifica explícitamente.
choices Lista de valores de tipo subyacente None Lista opcional de valores permitidos.
validator Función None

Función opcional para validar y posiblemente forzar el valor.

Se llamará con argumentos (prop, value) y debe mostrar el valor (posiblemente forzado) o elevar una excepción. Volver a llamar a la función en un valor forzado no debería modificar más el valor. (Por ejemplo, si muestra value.strip() o value.lower() está bien, pero no value + '$'). También puede mostrar None, que significa "sin cambio". Consulta también Escribir subclases de propiedades

verbose_name string None

Etiqueta HTML opcional para usar en formularios web de marcos de trabajo, como jinja2.

Propiedades repetidas

Cualquier propiedad con repeated=True se convierte en propiedad repetida. La propiedad toma una lista de valores del tipo subyacente, en lugar de un solo valor. Por ejemplo, el valor de una propiedad definida con IntegerProperty(repeated=True) es una lista de número enteros.

Cloud Datastore puede ver varios valores de esa propiedad. Se crea un registro de índice separado para cada valor. Esto afecta la semántica de consulta; consulta Consultar propiedades repetidas para ver un ejemplo.

Este ejemplo usa una propiedad repetida:

class Article(ndb.Model):
    title = ndb.StringProperty()
    stars = ndb.IntegerProperty()
    tags = ndb.StringProperty(repeated=True)
...
article = Article(
    title='Python versus Ruby',
    stars=3,
    tags=['python', 'ruby'])
article.put()

Esto crea una entidad de Cloud Datastore con los contenidos siguientes:

assert article.title == 'Python versus Ruby'
assert article.stars == 3
assert sorted(article.tags) == sorted(['python', 'ruby'])

Cuando se consulta por la propiedad tags, esta entidad satisfará una consulta para 'python' o 'ruby'.

Cuando se actualiza una propiedad repetida, puedes asignarle una lista nueva o mutar la lista existente allí. Cuando asignas una lista nueva, los tipos de los elementos de lista se validan inmediatamente. Los tipos de artículo no válidos (por ejemplo, asignar [1, 2] para art.tags más arriba) muestra una excepción. Cuando mutas la lista, el cambio no se valida inmediatamente. En su lugar, el valor se validará cuando escribas la entidad en Cloud Datastore.

Cloud Datastore conserva el orden de los elementos de lista en una propiedad repetida, por lo que puede asignar algún significado a su orden.

Propiedades de fecha y hora

Hay tres tipos de propiedades disponibles para almacenar valores relacionados con la fecha y la hora:

  • DateProperty
  • TimeProperty
  • DateTimeProperty

Estos toman valores pertenecientes a las clases correspondientes (date, time, datetime) del módulo estándar de Python datetime. El más general de los tres es DateTimeProperty, que denota tanto una fecha del calendario como una hora del día; los otros son ocasionalmente útiles para fines especiales que son obligatorios en una fecha (como una fecha de nacimiento) o en una hora (como una hora de reunión). Por razones técnicas, DateProperty y TimeProperty son subclases de DateTimeProperty, pero no debes depender de esta relación de herencia (y ten en cuenta que difiere de las relaciones de herencia entre las clases subyacentes definidas por el módulo datetime mismo).

Nota: Los tiempos de reloj de App Engine siempre se expresan en tiempo universal coordinado (UTC). Esto es relevante si usas la fecha o la hora actuales (datetime.datetime.now()) como un valor o una conversión entre objetos datetime y marcas de tiempo POSIX o tuplas de tiempo. Sin embargo, no se almacena información explícita de la zona horaria en Cloud Datastore, por lo que, si tienes cuidado, puedes usarlos para representar las horas locales en cualquier zona horaria, si usas la hora actual o las conversiones.

Cada una de estas propiedades tiene dos opciones de palabras clave booleanas adicionales:

Opción Descripción
auto_now_add Establece la propiedad en la fecha/hora actual cuando se crea la entidad. Puedes anular manualmente esta propiedad. Cuando la entidad se actualiza, la propiedad no cambia. Para ese comportamiento, usa auto_now.
auto_now Establece la propiedad en la fecha/hora actual cuando se crea la entidad y cada vez que se actualiza.

Estas opciones no se pueden combinar con repeated=True. Ambas son predeterminadas para False; si ambas están configuradas en True, auto_now tiene prioridad. Es posible anular el valor de una propiedad con auto_now_add=True, pero no para uno con auto_now=True. El valor automático no se genera hasta que se escribe la entidad; es decir, estas opciones no proporcionan valores predeterminados dinámicos. (Estos detalles difieren de la API de db anterior).

Nota: Cuando una transacción que escribe una propiedad con auto_now_add=True falla y se vuelve a intentar, se reutilizará el mismo valor de tiempo que en el intento original en lugar de actualizarlo hasta el momento del reintento. Si la transacción falla de forma permanente, el valor de la propiedad se seguirá estableciendo en la copia en memoria de la entidad.

Propiedades estructuradas

Puedes estructurar las propiedades de un modelo. Por ejemplo, puedes definir una clase de modelo Contact que contenga una lista de direcciones, cada una con estructura interna. Las propiedades estructuradas (del tipo StructuredProperty) te permiten hacer eso; por ejemplo:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
guido = Contact(
    name='Guido',
    addresses=[
        Address(
            type='home',
            city='Amsterdam'),
        Address(
            type='work',
            street='Spear St',
            city='SF')])

guido.put()

Esto crea una única entidad de Cloud Datastore con las propiedades siguientes:

assert guido.name == 'Guido'
addresses = guido.addresses
assert addresses[0].type == 'home'
assert addresses[1].type == 'work'
assert addresses[0].street is None
assert addresses[1].street == 'Spear St'
assert addresses[0].city == 'Amsterdam'
assert addresses[1].city == 'SF'

Si se vuelve a leer, esa entidad reconstruye exactamente la entidad de Contact original. Aunque las instancias de Address se definen con la misma sintaxis que las clases de modelo, no son entidades de pleno derecho. No tienen sus propias claves en Cloud Datastore. No se pueden recuperar independientemente de la entidad de Contact a la que pertenecen. Sin embargo, una aplicación puede consultar los valores de sus campos individuales; consulta Filtrar por valores de propiedad estructurada. Ten en cuenta que address.type, address.street y address.city se leen como arreglos paralelos desde el punto de vista de Cloud Datastore, pero la biblioteca de NDB oculta este aspecto y construye la lista correspondiente de instancias de Address.

Puedes especificar las opciones de propiedad para propiedades estructuradas (excepto indexed). El nombre de Cloud Datastore es el segundo argumento de posicionamiento en este caso (el primero es la clase de modelo usada para definir la subestructura).

Cuando no necesitas consultar las propiedades internas de una subestructura, puedes usar una propiedad local estructurada (LocalStructuredProperty) en su lugar. Si reemplazas StructuredProperty con LocalStructuredProperty en el ejemplo anterior, el comportamiento del código de Python es el mismo, pero Cloud Datastore ve solo un blob opaco para cada dirección. La entidad guido creada en el ejemplo se almacenaría de esta forma: name = 'Guido' address = <opaque blob for {'type': 'home', 'city': 'Amsterdam'}> address = <opaque blob for {'type': 'work', 'city': 'SF', 'street': 'Spear St'}>

La entidad se leerá correctamente. Como las propiedades de este tipo siempre están sin indexar, no puedes consultar los valores de dirección.

Nota: Una StructuredProperty con una propiedad anidada (esté o no estructurada) admite solo una capa única de propiedades repetidas. Se puede repetir la StructuredProperty o la propiedad anidada, pero no ambas. Una solución alternativa es usar LocalStructuredProperty, que no tiene esta restricción (pero no permite consultas sobre los valores de sus propiedades).

Propiedades computadas

Las propiedades computadas (ComputedProperty) son propiedades de solo lectura cuyo valor se calcula a partir de otros valores de propiedad mediante una función suministrada por la aplicación. Ten en cuenta que una propiedad calculada solo admite los tipos que son compatibles con propiedades genéricas. El valor calculado se escribe en Cloud Datastore para que se pueda consultar y mostrar en el lector de Cloud Datastore, pero el valor almacenado se ignora cuando la entidad vuelve a leer desde Cloud Datastore; por el contrario, el valor se vuelve a calcular llamando a la función cada vez que se solicita el valor. Por ejemplo:

class SomeEntity(ndb.Model):
    name = ndb.StringProperty()
    name_lower = ndb.ComputedProperty(lambda self: self.name.lower())
...
entity = SomeEntity(name='Nick')
entity.put()

Esto almacena una entidad con los valores de propiedad siguientes:

assert entity.name == 'Nick'
assert entity.name_lower == 'nick'

Si cambiamos el nombre a 'Nickie' y pedimos el valor de name_lower, muestra 'nickie':

entity.name = 'Nick'
assert entity.name_lower == 'nick'
entity.name = 'Nickie'
assert entity.name_lower == 'nickie'

Nota: Usa ComputedProperty si la aplicación consulta por el valor computado. Si solo deseas usar la versión derivada en el código de Python, define un método normal o usa la función @property de Python.

Nota: Si creas un modelo sin una clave especificada manualmente y, en su lugar, confías en Cloud Datastore para generar automáticamente un ID de la entidad, entonces en tu primer put() un ComputedProperty no podrá leer el campo de ID, ya que el campo se calcula antes de que se genere el ID. Si necesitas una ComputedProperty que use el ID de la entidad, puedes usar el método allocate_ids para generar un ID y una clave con las que crear la entidad, de modo que tu ComputedProperty pueda hacer referencia a esa ID en el primer put() de la entidad.

Propiedades del mensaje del protocolo de RPC de Google

La biblioteca del Google Protocol RPC usa objetos Message para datos estructurados; pueden representar solicitudes de RPC, respuestas o demás elementos. NDB proporciona una API para almacenar objetos Message del Protocolo de RPC de Google como propiedades de la entidad. Supongamos que defines una subclase de Message:

from protorpc import messages
...
class Note(messages.Message):
    text = messages.StringField(1, required=True)
    when = messages.IntegerField(2)

Puedes almacenar objetos Note en Cloud Datastore como valores de propiedad de la entidad con la API msgprop de NDB.

from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
...
class NoteStore(ndb.Model):
    note = msgprop.MessageProperty(Note, indexed_fields=['when'])
    name = ndb.StringProperty()
...
my_note = Note(text='Excellent note', when=50)

ns = NoteStore(note=my_note, name='excellent')
key = ns.put()

new_notes = NoteStore.query(NoteStore.note.when >= 10).fetch()

Si deseas consultar los nombres de los campos, estos deben estar indexados. Puedes especificar una lista de nombres de campo que se indexarán con el parámetro indexed_fields para MessageProperty.

MessageProperty admite muchas las opciones de propiedad, pero no todas. Es compatible con:

  • name
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Las propiedades de mensaje no admiten la opción de propiedad indexed; no se pueden indexar los valores de Message. (Puedes indexar los campos de un mensaje como se describe anteriormente).

Los mensajes anidados (con MessageField) también funcionan:

class Notebook(messages.Message):
    notes = messages.MessageField(Note, 1, repeated=True)
...
class SignedStorableNotebook(ndb.Model):
    author = ndb.StringProperty()
    nb = msgprop.MessageProperty(
        Notebook, indexed_fields=['notes.text', 'notes.when'])

MessageProperty tiene una opción de propiedad especial, protocol, que especifica cómo se serializa el objeto de mensaje en Cloud Datastore. Los valores son nombres de protocolo que usa la clase protorpc.remote.Protocols. Los nombres de protocolo compatibles son protobuf y protojson. El valor predeterminado es protobuf.

msgprop también define EnumProperty, un tipo de propiedad que se puede utilizar para almacenar un valor protorpc.messages.Enum en una entidad. Ejemplo:

class Color(messages.Enum):
    RED = 620
    GREEN = 495
    BLUE = 450
...
class Part(ndb.Model):
    name = ndb.StringProperty()
    color = msgprop.EnumProperty(Color, required=True)
...
p1 = Part(name='foo', color=Color.RED)
print p1.color  # prints "RED"

EnumProperty almacena el valor como un número entero; de hecho, EnumProperty es una subclase de IntegerProperty. Esto implica que puedes cambiar el nombre de sus valores de enumeración sin tener que modificar las entidades ya almacenadas, pero no puedes renumerarlos.

EnumProperty admite las opciones de propiedad siguientes:

  • name
  • indexed
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Acerca de los modelos de entidad NDB

Un modelo de entidad NDB puede definir propiedades. Las propiedades de la entidad son un poco como miembros de datos de las clases de Python, una forma estructurada de almacenar datos; también son como campos en un esquema de base de datos.

Una aplicación típica define un modelo de datos definiendo una clase que hereda de Model con algunos atributos de clase de propiedad. Por ejemplo,

from google.appengine.ext import ndb
...
class Account(ndb.Model):
    username = ndb.StringProperty()
    userid = ndb.IntegerProperty()
    email = ndb.StringProperty()

Aquí, username, userid y email son propiedades de Account.

Hay muchos otros tipos de propiedades. Algunos son útiles para representar fechas y horas, y tienen funciones de actualización automática convenientes.

Una aplicación puede ajustar el comportamiento de una propiedad especificando opciones en la propiedad. Estos pueden facilitar la validación, establecer valores predeterminados o cambiar la indexación de consultas.

Un modelo puede tener propiedades más complejas. Las propiedades repetidas son como listas. Las propiedades estructuradas son como objetos. Las propiedades computadas de solo lectura se definen a través de funciones; esto facilita la definición de una propiedad en términos de una o más propiedades. Los modelos de Expando pueden definir propiedades dinámicamente.

¿Te sirvió esta página? Envíanos tu opinión:

Enviar comentarios sobre…

Entorno estándar de App Engine para Python