Riferimento alle proprietà delle entità

Firestore in modalità Datastore (Datastore) supporta diversi tipi di dati per i valori delle proprietà. tra cui:

  • Numeri interi
  • Numeri con virgola mobile
  • Stringhe
  • Date
  • Dati binari

Per un elenco completo dei tipi, consulta Proprietà e tipi di valori.

Proprietà e tipi di valori

I valori dei dati associati a un'entità sono costituiti da una o più proprietà. Ogni proprietà ha un nome e uno o più valori. Una proprietà può avere valori di più di un tipo e due entità possono avere valori di tipi diversi per la stessa proprietà. Le proprietà possono essere indicizzate o non indicizzate (le query che ordinano o filtrano su una proprietà P ignoreranno le entità in cui P non è indicizzato). Un'entità può avere al massimo 20.000 proprietà indicizzate.

Sono supportati i seguenti tipi di valori:

Quando una query riguarda una proprietà con valori di tipi misti, Datastore utilizza un ordinamento deterministico basato sulle rappresentazioni interne:

  1. Valori null
  2. Numeri a virgola fissa
    • Numeri interi
    • Date e ore
  3. Valori booleani
  4. Sequenze di byte
    • Stringa Unicode
    • Chiavi dell'archivio BLOB
  5. Numeri con virgola mobile
  6. Chiavi Datastore

Poiché le stringhe di testo lunghe e le stringhe di byte lunghi non sono indicizzate, non hanno un ordine definito.

Tipi di proprietà

NDB supporta i seguenti tipi di proprietà:

Tipo di immobile Descrizione
IntegerProperty Numero intero con firma a 64 bit
FloatProperty Numero in virgola mobile a precisione doppia
BooleanProperty Booleano
StringProperty Stringa Unicode; fino a 1500 byte, indicizzata
TextProperty Stringa Unicode; lunghezza illimitata, non indicizzata
BlobProperty Stringa di byte non interpretata:
se imposti indexed=True, fino a 1500 byte, indicizzato;
se indexed è False (valore predefinito), lunghezza illimitata, non indicizzato.
Argomento facoltativo parola chiave: compressed.
DateTimeProperty Data e ora (consulta Proprietà Data e ora)
DateProperty Data (consulta Proprietà Data e ora)
TimeProperty Ora (consulta Proprietà Data e ora)
GeoPtProperty Posizione geografica. Questo è un oggetto ndb.GeoPt. L'oggetto ha gli attributi lat e lon, entrambi in virgola mobile. Puoi costruirne uno con due valori in virgola mobile come ndb.GeoPt(52.37, 4.88) o con una stringa ndb.GeoPt("52.37, 4.88"). (In realtà è la stessa classe di db.GeoPt)
KeyProperty Chiave Datastore
Argomento facoltativo parola chiave: kind=kind, per richiedere che le chiavi assegnate a questa proprietà abbiano sempre il tipo indicato. Può essere una stringa o una sottoclasse Model.
BlobKeyProperty Chiave dell'archivio BLOB
Corrisponde a BlobReferenceProperty nella precedente API db, ma il valore della proprietà è BlobKey anziché BlobInfo; puoi utilizzarlo per creare un BlobInfo utilizzando BlobInfo(blobkey)
UserProperty Oggetto utente.
StructuredProperty Include un tipo di modello all'interno di un altro, per valore (consulta Proprietà strutturate)
LocalStructuredProperty Come StructuredProperty, ma la rappresentazione sul disco è un blob opaco e non è indicizzata (vedi Proprietà strutturate).
Argomento facoltativo parola chiave: compressed.
JsonProperty Il valore è un oggetto Python (come un elenco, un dict o una stringa) serializzabile tramite il modulo json di Python; Datastore archivia la serializzazione JSON come un BLOB. Non indicizzato per impostazione predefinita.
Argomento facoltativo parola chiave: compressed.
PickleProperty Il valore è un oggetto Python (come un elenco, un dict o una stringa) serializzabile mediante il protocollo pickle di Python; Datastore archivia la serializzazione del comando come BLOB. Non indicizzato per impostazione predefinita.
Argomento facoltativo parola chiave: compressed.
GenericProperty Valore generico
Utilizzato principalmente dalla classe Expando, ma anche utilizzabile esplicitamente. Può essere uno dei seguenti tipi: int, long, float, bool, str, unicode, datetime, Key, BlobKey, GeoPt, User, None.
ComputedProperty Valore calcolato da altre proprietà da una funzione definita dall'utente;utente. (Vedi Proprietà calcolate.)

Alcune di queste proprietà hanno un argomento parola chiave facoltativo, compressed. Se la proprietà ha compressed=True, i dati vengono compressi con gzip su disco. Richiede meno spazio, ma necessita di CPU per codificare/decodificare durante le operazioni di scrittura e lettura.

Sia la compressione che la decompressione sono "lazy"; il valore di una proprietà compressa viene decompresso solo la prima volta che vi accedi. Se leggi un'entità contenente un valore di proprietà compressa e la scrivi senza accedere alla proprietà compressa, questa non verrà decompressa e compressa. Anche la cache nel contesto partecipa a questo schema lento, ma memcache archivia sempre il valore compresso per le proprietà compresse.

A causa del tempo di CPU aggiuntivo necessario per la compressione, di solito è preferibile utilizzare le proprietà compresse solo se i dati sarebbero troppo grandi per non farlo. Ricorda che la compressione basata su gzip in genere non è efficace per le immagini e altri dati multimediali, poiché questi formati vengono già compressi utilizzando un algoritmo di compressione specifico per i contenuti multimediali (ad esempio JPEG per le immagini).

Opzioni proprietà

La maggior parte dei tipi di proprietà supporta alcuni argomenti standard. Il primo è un argomento posizionale facoltativo che specifica il nome del datastore della proprietà. Puoi utilizzarlo per assegnare alla proprietà un nome nel datastore diverso da quello usato nel punto di vista dell'applicazione. Un uso comune di questa condizione è ridurre lo spazio in Datastore, consentendo a Datastore di utilizzare nomi di proprietà abbreviati, mentre il tuo codice utilizza nomi più lunghi e più significativi. Ad esempio:

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

Questo è particolarmente utile per le proprietà ripetute per le quali prevedi molti valori per entità.

Inoltre, la maggior parte dei tipi di proprietà supporta i seguenti argomenti delle parole chiave:

Argomento Tipo Predefinito Descrizione
indexed bool Di solito True Includi la proprietà negli indici di Datastore; se False, non è possibile eseguire query sui valori, ma le scritture sono più veloci. Non tutti i tipi di proprietà supportano l'indicizzazione; l'impostazione di indexed su True non va a buon fine.
Le proprietà non indicizzate costano meno operazioni di scrittura rispetto alle proprietà indicizzate.
repeated bool False Il valore della proprietà è un elenco Python contenente i valori del tipo sottostante (vedi Proprietà ripetute).
Non può essere combinata con required=True o default=True.
required bool False Per la proprietà deve essere specificato un valore.
default Tipo sottostante della proprietà Nessuna Valore predefinito della proprietà se nessuno è esplicitamente specificato.
choices Elenco di valori del tipo sottostante None Elenco facoltativo di valori consentiti.
validator Funzione None

Funzione facoltativa per convalidare ed eventualmente forzare il valore.

Verrà chiamato con gli argomenti (prop, value) e dovrebbe restituire il valore (possibilmente forzato) o generare un'eccezione. Se chiami di nuovo la funzione in un valore forzato, il valore non dovrebbe essere modificato. Ad esempio, restituire value.strip() o value.lower() è consentito, ma non value + '$'. Potrebbe anche restituire None, che significa "nessuna modifica". Consulta anche Scrittura di sottoclassi di proprietà

verbose_name string None

Etichetta HTML facoltativa da utilizzare nei framework di moduli web come jinja2.

Proprietà ripetute

Qualsiasi proprietà con repeated=True diventa una proprietà ripetuta. La proprietà accetta un elenco di valori del tipo sottostante, anziché un singolo valore. Ad esempio, il valore di una proprietà definita con IntegerProperty(repeated=True) è un elenco di numeri interi.

Datastore potrebbe visualizzare più valori per questa proprietà. Per ogni valore viene creato un record di indice separato. Questo influisce sulla semantica della query; consulta Esecuzione di query per proprietà ripetute per un esempio.

Questo esempio utilizza una proprietà ripetuta:

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()

Viene creata un'entità Datastore con i seguenti contenuti:

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

Quando esegui una query per la proprietà tags, questa entità soddisferà una query per 'python' o 'ruby'.

Quando aggiorni una proprietà ripetuta, puoi assegnarle un nuovo elenco o modificare l'elenco esistente. Quando assegni un nuovo elenco, i tipi di elementi dell'elenco vengono convalidati immediatamente. I tipi di elementi non validi (ad esempio l'assegnazione di [1, 2] a art.tags sopra) generano un'eccezione. Quando modifichi l'elenco, la modifica non viene convalidata immediatamente. Il valore verrà invece convalidato quando scrivi l'entità in Datastore.

Datastore conserva l'ordine degli elementi di elenco in una proprietà ripetuta, quindi puoi assegnare un significato al loro ordinamento.

Proprietà data e ora

Sono disponibili tre tipi di proprietà per l'archiviazione dei valori relativi a data e ora:

  • DateProperty
  • TimeProperty
  • DateTimeProperty

Assumono valori appartenenti alle classi corrispondenti (date, time, datetime) del modulo Python datetime standard. Il più generico dei tre è DateTimeProperty, che indica sia una data di calendario sia un'ora del giorno; le altre sono occasionalmente utili per scopi speciali che richiedono solo una data (ad esempio la data di nascita) o solo un'ora (ad esempio l'orario di una riunione). Per motivi tecnici, DateProperty e TimeProperty sono sottoclassi di DateTimeProperty, ma non devi dipendere da questa relazione di ereditarietà (ricorda che è diversa dalle relazioni di ereditarietà tra le classi sottostanti definite dal modulo datetime stesso).

Nota: gli orari di orario di App Engine sono sempre espressi nel tempo Universale coordinato (UTC). Questo diventa pertinente se utilizzi la data o l'ora corrente (datetime.datetime.now()) come valore o converti tra oggetti data/ora e timestamp POSIX o tuple temporali. Tuttavia, in Datastore non vengono archiviate informazioni esplicite sul fuso orario; pertanto, se fai attenzione, puoi utilizzarle per rappresentare l'ora locale in qualsiasi fuso orario, se utilizzi l'ora corrente o le conversioni.

Ognuna di queste proprietà include due opzioni aggiuntive per le parole chiave booleane:

Opzione Descrizione
auto_now_add Imposta la proprietà sulla data/ora corrente quando viene creata l'entità. Puoi eseguire manualmente l'override di questa proprietà. Quando l'entità viene aggiornata, la proprietà non cambia. Per questo comportamento, utilizza auto_now.
auto_now Imposta la proprietà sulla data/ora corrente quando l'entità viene creata e ogni volta che viene aggiornata.

Queste opzioni non possono essere combinate con repeated=True. Il valore predefinito è False; se entrambi sono impostati su True, auto_now ha la precedenza. È possibile eseguire l'override del valore per una proprietà con auto_now_add=True, ma non per una con auto_now=True. Il valore automatico non viene generato finché l'entità non viene scritta; in altre parole, queste opzioni non forniscono valori predefiniti dinamici. Questi dettagli sono diversi dalla precedente API db.

Nota: quando una transazione per la scrittura di una proprietà con auto_now_add=True non va a buon fine e viene ripetuta in un secondo momento, riutilizza lo stesso valore temporale del tentativo originale anziché aggiornarlo al momento del nuovo tentativo. Se la transazione non va a buon fine in modo permanente, il valore della proprietà verrà comunque impostato nella copia in memoria dell'entità.

Proprietà strutturate

Puoi strutturare le proprietà di un modello. Ad esempio, puoi definire una classe di modello Contact contenente un elenco di indirizzi, ciascuno con struttura interna. Le proprietà strutturate (tipo StructuredProperty) ti consentono di farlo, ad esempio:

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()

Viene creata una singola entità Datastore con le seguenti proprietà:

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'

Leggendo questo tipo di entità, viene ricostruita esattamente l'entità originale Contact. Sebbene le istanze Address siano definite utilizzando la stessa sintassi delle classi del modello, non sono entità complete. Non hanno le proprie chiavi in Datastore. Non possono essere recuperati indipendentemente dall'entità Contact a cui appartengono. Un'applicazione può, tuttavia, eseguire una query sui valori dei singoli campi; consulta la pagina relativa al filtro dei valori delle proprietà strutturate. Tieni presente che address.type, address.street e address.city sono visualizzati come array paralleli dal punto di vista di Datastore, ma la libreria NDB nasconde questo aspetto e crea l'elenco corrispondente di istanze Address.

Puoi specificare le consuete opzioni delle proprietà per le proprietà strutturate (tranne indexed). In questo caso, il nome Datastore è il secondo argomento di posizione (il primo è la classe di modello utilizzata per definire la sottostruttura).

Quando non devi eseguire query sulle proprietà interne di una sottostruttura, puoi utilizzare una proprietà strutturata locale (LocalStructuredProperty). Se sostituisci StructuredProperty con LocalStructuredProperty nell'esempio precedente, il comportamento del codice Python è lo stesso, ma Datastore vede solo un BLOB opaco per ogni indirizzo. L'entità guido creata nell'esempio verrebbe archiviata come segue: name = 'Guido' address = <opaque blob for {'type': 'home', 'city': 'Amsterdam'}> address = <opaque blob for {'type': 'work', 'city': 'SF': '> Spearstreet

L'entità verrà letta correttamente. Poiché le proprietà di questo tipo non sono sempre indicizzate, non puoi eseguire query per i valori degli indirizzi.

Nota: un elemento StructuredProperty con una proprietà nidificata (indipendentemente dal fatto che sia strutturato o meno) supporta un solo livello di proprietà ripetute. È possibile ripetere StructuredProperty oppure la proprietà nidificata, ma non entrambe. Una soluzione alternativa consiste nell'utilizzare LocalStructuredProperty, che non ha questo vincolo (ma non consente query sui valori delle sue proprietà).

Proprietà calcolate

Le proprietà calcolate (ComputedProperty) sono proprietà di sola lettura il cui valore viene calcolato da altri valori di proprietà da una funzione fornita dall'applicazione. Nota che una proprietà calcolata supporta solo i tipi supportati dalle proprietà generiche. Il valore calcolato viene scritto in Datastore in modo che possa essere interrogato e visualizzato nel visualizzatore Datastore, ma il valore archiviato viene ignorato quando l'entità viene letta da Datastore. Al contrario, il valore viene ricalcolato chiamando la funzione ogni volta che viene richiesto il valore. Ad esempio:

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

Viene archiviata un'entità con i seguenti valori di proprietà:

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

Se cambiamo il nome in "Nickie" e chiediamo il valore di name_lower, viene restituito "nickie":

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

Nota: utilizza ComputedProperty se l'applicazione esegue query per il valore calcolato. Se vuoi solo utilizzare la versione derivata nel codice Python, definisci un metodo regolare o utilizza l'integrazione @property di Python.

Nota: se crei un modello senza una chiave specificata manualmente e ti affidi a Datastore per generare automaticamente l'ID dell'entità, il primo put() ComputedProperty non potrà leggere il campo ID poiché il campo viene calcolato prima della generazione dell'ID. Se hai bisogno di un ComputedProperty che utilizza l'ID dell'entità, puoi utilizzare il metodo allocate_ids per generare un ID e una chiave con cui creare l'entità, in modo che ComputedProperty possa fare riferimento a quell'ID nella prima put() dell'entità.

Proprietà dei messaggi RPC del protocollo Google

La libreria RPC di Google Protocol utilizza gli oggetti Message per i dati strutturati, che possono rappresentare richieste RPC, risposte o altri elementi. NDB fornisce un'API per l'archiviazione degli oggetti Message RPC del protocollo Google come proprietà dell'entità. Supponi di definire una sottoclasse Message:

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

Puoi archiviare gli oggetti Note in Datastore come valori di proprietà entità utilizzando l'API msgprop di 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()

Se vuoi eseguire query per nomi di campi, questi devono essere indicizzati. Puoi specificare un elenco di nomi di campi che verranno indicizzati con il parametro indexed_fields in MessageProperty.

MessageProperty supporta molte opzioni delle proprietà, ma non tutte. Supporta:

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

Le proprietà del messaggio non supportano l'opzione della proprietà indexed; non puoi indicizzare i valori Message. Puoi indicizzare i campi di un messaggio come descritto sopra.

I messaggi nidificati (utilizzando MessageField) funzionano anche:

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 ha un'opzione di proprietà speciale, protocol, che specifica in che modo l'oggetto del messaggio viene serializzato in Datastore. I valori sono nomi di protocollo utilizzati dalla classe protorpc.remote.Protocols. I nomi di protocollo supportati sono protobuf e protojson; il valore predefinito è protobuf.

msgprop definisce anche EnumProperty, un tipo di proprietà che può essere utilizzato per archiviare un valore protorpc.messages.Enum in un'entità. Esempio:

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 memorizza il valore come numero intero; infatti, EnumProperty è una sottoclasse di IntegerProperty. Ciò implica che puoi rinominare i valori di enumerazione senza dover modificare le entità già archiviate, ma non puoi rinumerarli.

EnumProperty supporta le seguenti opzioni delle proprietà:

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

Informazioni sui modelli di entità NDB

Un modello di entità NDB può definire le proprietà. Le proprietà delle entità sono un po' come i membri dei dati delle classi Python, un modo strutturato per conservare i dati; sono anche un po' come i campi in uno schema di database.

Un'applicazione tipica definisce un modello dei dati definendo una classe che eredita da Model con alcuni attributi di classe della proprietà. Ad esempio:


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

Qui, username, userid e email sono proprietà di Account.

Esistono diversi altri tipi di proprietà. Alcuni sono utili per rappresentare date e orari e hanno pratiche funzionalità di aggiornamento automatico.

Un'applicazione può regolare il comportamento di una proprietà specificando le opzioni sulla proprietà; queste possono facilitare la convalida, impostare valori predefiniti o modificare l'indicizzazione delle query.

Un modello può avere proprietà più complesse. Le proprietà ripetute sono di tipo elenco. Le proprietà strutturate sono simili agli oggetti. Le proprietà calcolate di sola lettura sono definite tramite funzioni. Ciò semplifica la definizione di una proprietà in termini di una o più altre proprietà. I modelli Espandi possono definire le proprietà in modo dinamico.