Creazione dei modelli di entità

Devi creare una classe di modello per l'entità. Puoi farlo in due modi:

  • Crea una classe di modello che definisce le proprietà dell'entità.
  • Crea una classe di modello espandibili che non definisca in anticipo le entità.

Questo documento descrive come creare ciascuno di questi tipi di classi di modelli. Descrive inoltre come creare un hook del modello, in modo che applicazione può eseguire del codice prima o dopo qualche tipo di operazioni, esempio, prima di ogni get().

Creazione di una classe di modello con proprietà

Prima di creare un'entità, devi creare una classe di modello che definisca uno o altre proprietà dell'entità. Ad esempio:

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

in cui vuoi che ogni entità Account abbia le proprietà per nome utente, ID utente e l'email.

Per un elenco completo dei tipi di proprietà, consulta la pagina Riferimento alle proprietà delle entità.

Creazione di una classe di modello Espandio

Non è necessario utilizzare una classe di modello che definisce le proprietà in anticipo. Una sottoclasse speciale del modello chiamata Expando modifica il comportamento delle sue entità, in modo che qualsiasi attributo assegnato venga salvato nel datastore. Nota che questi attributi non possano iniziare con un trattino basso.

Ecco come creare un modello Espandio:

class Mine(ndb.Expando):
    pass
...
e = Mine()
e.foo = 1
e.bar = 'blah'
e.tags = ['exp', 'and', 'oh']
e.put()

Questa operazione scrive un'entità nel datastore con un'etichetta Proprietà foo con valore intero 1, una proprietà bar con valore stringa 'blah', e una proprietà tag ripetuta con stringa valori 'exp', 'and' e 'oh'. Le proprietà vengono indicizzate e puoi controllarle utilizzando attributo _properties dell'entità:

return e._properties
# {
#     'foo': GenericProperty('foo'),
#     'bar': GenericProperty('bar'),
#     'tags': GenericProperty('tags', repeated=True)
# }

Un elemento Expando creato ottenendo un valore da il datastore ha proprietà per tutti i valori delle proprietà salvati nel datastore.

Un'applicazione può aggiungere proprietà predefinite Expando sottoclasse:

class FlexEmployee(ndb.Expando):
    name = ndb.StringProperty()
    age = ndb.IntegerProperty()
...
employee = FlexEmployee(name='Sandy', location='SF')

Viene assegnato a employee un attributo name con valore 'Sandy', un attributo age con valore None, e un attributo dinamico location con valore 'SF'.

Per creare una sottoclasse Expando con proprietà non indicizzate, imposta _default_indexed = False nella definizione della sottoclasse:

class Specialized(ndb.Expando):
    _default_indexed = False
...
e = Specialized(foo='a', bar=['b'])
return e._properties
# {
#     'foo': GenericProperty('foo', indexed=False),
#     'bar': GenericProperty('bar', indexed=False, repeated=True)
# }

Puoi anche impostare _default_indexed su un'entità Expando. In questo caso, influenzerà tutte le proprietà assegnate dopo l'impostazione.

Un'altra tecnica utile è eseguire query su un tipo Expando per una proprietà dinamica. R query simile alla seguente

FlexEmployee.query(FlexEmployee.location == 'SF')

non funzionerà, perché la classe non ha un oggetto proprietà per la posizione proprietà. Usa invece GenericProperty, la classe che Expando utilizza per le query proprietà:

FlexEmployee.query(ndb.GenericProperty('location') == 'SF')

Utilizzo di Model Hook

NDB offre un meccanismo di aggancio leggero. definendo un hook, un'applicazione possono eseguire del codice prima o dopo un certo tipo di operazioni; ad esempio Model potrebbe eseguire alcune funzioni prima ogni get().

Una funzione hook viene eseguita quando si utilizzano le versioni sincrona, asincrona e multiversione del metodo appropriato. Ad esempio, un "pre-lancio" si applica a tutti gli elementi get(), get_async() e get_multi(). Esistono versioni pre-RPC e post-RPC di ogni gancio.

Gli hook possono essere utili per:

  • memorizzazione nella cache delle query
  • controllo dell'attività di Cloud Datastore per utente
  • imitazione dei trigger di database

L'esempio seguente mostra come definire le funzioni hook:

from google.appengine.ext import ndb
...
class Friend(ndb.Model):
    name = ndb.StringProperty()

    def _pre_put_hook(self):
        _notify('Gee wiz I have a new friend!')

    @classmethod
    def _post_delete_hook(cls, key, future):
        _notify('I have found occasion to rethink our friendship.')
...
f = Friend()
f.name = 'Carole King'
f.put()  # _pre_put_hook is called
fut = f.key.delete_async()  # _post_delete_hook not yet called
fut.get_result()  # _post_delete_hook is called

Se usi post-hook con API asincrone, gli hook vengono attivati chiamando check_result(), get_result() o restituisce (all'interno di un tasklet) una query asincrona del metodo di pagamento. Gli hook di post non verificano se la RPC è riuscita; l'hook viene eseguito indipendentemente dall'errore.

Tutti i post-hook hanno un futuro alla fine della firma della chiamata. Questo oggetto Future contiene il risultato dell'azione. Puoi chiamare get_result() su questo Future per recuperare il risultato; puoi essere certo che get_result() non verrà bloccato, poiché Future è completo quando viene chiamato l'hook.

Se viene sollevata un'eccezione durante un pre-hook, la richiesta non viene eseguita. Sebbene gli hook vengano attivati all'interno dei metodi <var>*</var>_async, non puoi prerilascia una RPC generando tasklets.Return in un hook pre-RPC.

Passaggi successivi