Archiviazione dei dati in Datastore


Questa parte della procedura dettagliata sul codice del guestbook Python mostra come archiviare i dati strutturati in Datastore. Con App Engine e Datastore, non devi preoccuparti della distribuzione, della replica e del bilanciamento del carico dei dati. Ciò viene fatto per te dietro una semplice API e avrai anche un potente motore di query e transazioni.

Questa pagina fa parte di un tutorial multi pagina. Per partire dall'inizio e vedere le istruzioni per la configurazione, vai a Creare un guestbook.

Archiviazione dei saluti inviati

I dati vengono scritti in Datastore in oggetti noti come entità. Ogni entità ha una chiave che la identifica in modo univoco. Un'entità può facoltativamente designare un'altra entità come parent; la prima entità è un'entità parent dell'entità padre. Le entità nel datastore formano quindi uno spazio strutturato in modo gerarchico simile alla struttura di directory di un file system. Per informazioni dettagliate, consulta Strutturare i dati per garantire un'elevata coerenza.

App Engine include un'API di modellazione dei dati per Python. Per utilizzare l'API di modellazione dei dati, l'app di esempio importa il modulo google.appengine.ext.ndb. Ogni saluto include il nome dell'autore, il contenuto del messaggio e la data e l'ora in cui il messaggio è stato pubblicato. L'app mostra i messaggi in ordine cronologico. Il codice seguente definisce il modello dei dati:

class Author(ndb.Model):
    """Sub model for representing an author."""
    identity = ndb.StringProperty(indexed=False)
    email = ndb.StringProperty(indexed=False)

class Greeting(ndb.Model):
    """A main model for representing an individual Guestbook entry."""
    author = ndb.StructuredProperty(Author)
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

Il codice definisce un modello Greeting con tre proprietà: author il cui valore è un oggetto Author con l'indirizzo email e l'identità dell'autore, content il cui valore è una stringa e date il cui valore è datetime.datetime.

Alcuni costruttori di proprietà utilizzano parametri per configurare ulteriormente il loro comportamento. Se trasmetti il costruttore ndb.StringProperty, il parametro indexed=False indica che i valori di questa proprietà non verranno indicizzati. In questo modo vengono salvate le scritture non necessarie perché l'app non utilizza mai quella proprietà in una query. Il passaggio del costruttore ndb.DateTimeProperty un parametro auto_now_add=True configura il modello in modo da assegnare automaticamente ai nuovi oggetti un timestamp datetime relativo all'ora di creazione dell'oggetto, se l'applicazione non fornisce un valore in altro modo. Per un elenco completo dei tipi di proprietà e delle relative opzioni, consulta Proprietà NDB.

L'applicazione utilizza il modello dati per creare nuovi oggetti Greeting e inserirli in Datastore. Il gestore Guestbook crea nuovi saluti e li salva nel datastore:

class Guestbook(webapp2.RequestHandler):

    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each
        # Greeting is in the same entity group. Queries across the
        # single entity group will be consistent. However, the write
        # rate to a single entity group should be limited to
        # ~1/second.
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = Author(
                    identity=users.get_current_user().user_id(),
                    email=users.get_current_user().email())

        greeting.content = self.request.get('content')
        greeting.put()

        query_params = {'guestbook_name': guestbook_name}
        self.redirect('/?' + urllib.urlencode(query_params))

Questo gestore Guestbook crea un nuovo oggetto Greeting, quindi imposta le relative proprietà author e content con i dati pubblicati dall'utente. L'entità padre di Greeting è un'entità Guestbook. Non è necessario creare l'entità Guestbook prima di impostarla come entità padre di un'altra entità. In questo esempio, l'elemento padre viene utilizzato come segnaposto per scopi di transazione e coerenza. Consulta la pagina Transazioni per ulteriori informazioni. Gli oggetti che condividono un ancestor comune appartengono allo stesso gruppo di entità. Il codice non imposta la proprietà date, quindi date viene impostato automaticamente sul presente, utilizzando auto_now_add=True.

Infine, greeting.put() salva il nuovo oggetto nel datastore. Se avessimo acquisito questo oggetto da una query, put() avrebbe aggiornato l'oggetto esistente. Poiché abbiamo creato questo oggetto con il creatore del modello, put() aggiunge il nuovo oggetto al datastore.

Poiché l'esecuzione di query in Datastore è a coerenza elevata solo all'interno dei gruppi di entità, il codice assegna tutti i saluti di un libro allo stesso gruppo di entità impostando lo stesso elemento padre per ciascun saluto. Ciò significa che l'utente vede sempre un saluto subito dopo la sua scrittura. Tuttavia, la frequenza con cui puoi scrivere nello stesso gruppo di entità è limitata a una scrittura nel gruppo di entità al secondo. Quando progetti un'applicazione reale, devi tenere a mente questo aspetto. Tieni presente che, utilizzando servizi come Memcache, puoi ridurre la possibilità che un utente veda risultati obsoleti quando esegue una query su più gruppi di entità dopo una scrittura.

Recupero dei saluti inviati

Datastore dispone di un sofisticato motore di query per i modelli di dati. Poiché Datastore non è un database relazionale tradizionale, le query non vengono specificate tramite SQL. Le query sui dati vengono invece eseguite in due modi: utilizzando query sul datastore oppure un linguaggio di query simile a SQL chiamato GQL. Per accedere all'intera gamma di funzionalità di query di Datastore, consigliamo di utilizzare query su GQL.

Il gestore MainPage recupera e visualizza i saluti inviati in precedenza. La chiamata greetings_query.fetch(10) esegue la query.

Scopri di più sugli indici Datastore

Ogni query in Datastore viene calcolata da uno o più indici, tabelle che mappano i valori delle proprietà ordinate alle chiavi di entità. In questo modo App Engine è in grado di fornire risultati rapidamente, a prescindere dalle dimensioni del datastore della tua applicazione. Molte query possono essere calcolate dagli indici integrati, ma per le query più complesse, Datastore richiede un indice personalizzato. Senza un indice personalizzato, Datastore non può eseguire queste query in modo efficiente.

Ad esempio, l'applicazione guestbook filtra per guestbook e ordina per data, utilizzando una query da predecessore e un ordinamento. Ciò richiede la specifica di un indice personalizzato nel file index.yaml dell'applicazione. Puoi modificare questo file manualmente o automaticamente eseguendo le query nell'applicazione localmente. Dopo che l'indice è stato definito in index.yaml, il deployment dell'applicazione eseguirà anche il deployment delle informazioni dell'indice personalizzato.

La definizione della query in index.yaml ha il seguente aspetto:

indexes:
- kind: Greeting
  ancestor: yes
  properties:
  - name: date
    direction: desc

Per saperne di più sugli indici di Datastore, consulta la pagina Indici di Datastore. Leggi ulteriori informazioni sulla specifica corretta per i file index.yaml in Configurazione dell'indice Python Datastore.