My favorites | Português | Sign in

Uso do armazenamento de dados

Armazenar dados em um aplicativo da web escalável pode ser complicado. Um usuário pode estar interagindo com muitos servidores da web em um dado momento, e a próxima solicitação do usuário pode ser para um servidor da web diferente do servidor que tratou a solicitação anterior. Todos os servidores da web precisam interagir com dados que também estão distribuídos em dezenas de máquinas, possivelmente em diferentes locais ao redor do mundo.

Você não precisa se preocupar com nada disso graças ao Google App Engine. A infra-estrutura do Google App Engine cuida de toda a distribuição, replicação e balanceamento de carga de dados por trás de uma simples API — e você obtém um poderoso mecanismo de consultas e transações.

Um exemplo completo usando o armazenamento de dados

Veja abaixo uma nova versão do helloworld/helloworld.py que armazena saudações no armazenamento de dados. O restante da página discute o conteúdo novo.

import cgi

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Greeting(db.Model):
  author = db.UserProperty()
  content = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

class MainPage(webapp.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')

    greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")

    for greeting in greetings:
      if greeting.author:
        self.response.out.write('<b>%s</b> wrote:' % greeting.author.nickname())
      else:
        self.response.out.write('An anonymous person wrote:')
      self.response.out.write('<blockquote>%s</blockquote>' %
                              cgi.escape(greeting.content))

    # Write the submission form and the footer of the page
    self.response.out.write("""
          <form action="/sign" method="post">
            <div><textarea name="content" rows="3" cols="60"></textarea></div>
            <div><input type="submit" value="Sign Guestbook"></div>
          </form>
        </body>
      </html>""")

class Guestbook(webapp.RequestHandler):
  def post(self):
    greeting = Greeting()

    if users.get_current_user():
      greeting.author = users.get_current_user()

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

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/sign', Guestbook)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

Substitua helloworld/helloworld.py por isso e recarregue http://localhost:8080/ no seu navegador. Poste algumas mensagens para verificar se as mensagens estão sendo armazenadas e exibidas corretamente.

Armazenamento das saudações enviadas

O Google App Engine inclui uma API de modelagem de dados para Python. Ela é semelhante à API de modelagem de dados do Django, mas utiliza o armazenamento de dados escalável do Google App Engine em segundo plano.

No caso do aplicativo de livro de visitas, queremos armazenar as saudações postadas pelos usuários. Cada saudação inclui o nome do autor, o conteúdo da mensagem e a data e a hora em que a mensagem foi postada, para podermos exibir as mensagens em ordem cronológica.

Para usar a API de modelagem de dados, importe o módulo google.appengine.ext.db:

from google.appengine.ext import db

O código a seguir define um modelo de dados para uma saudação:

class Greeting(db.Model):
  author = db.UserProperty()
  content = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

Isso define um modelo de Greeting com três propriedades: author, cujo valor é um objeto User; content, cujo valor é uma string, e date, cujo valor é um datetime.datetime.

Alguns construtores de propriedade recebem parâmetros para configurar ainda mais seu comportamento. Dar ao construtor db.StringProperty o parâmetro multiline=True significa que o valor desta propriedade pode conter caracteres de nova linha. Dar ao construtor db.DateTimeProperty o parâmetro auto_now_add=True configura o modelo para fornecer automaticamente uma date aos novos objetos, com a hora em que o objeto foi criado, caso o aplicativo não forneça nenhum valor. Para obter uma lista completa dos tipos de propriedade e suas opções, consulte a Referência de armazenamento de dados.

Agora que temos um modelo de dados para saudações, o aplicativo pode usar o modelo para criar novos objetos de Greeting e colocá-los no armazenamento de dados. A versão nova do manipulador Guestbook mostrada a seguir cria saudações novas e as salva no armazenamento de dados:

class Guestbook(webapp.RequestHandler):
  def post(self):
    greeting = Greeting()

    if users.get_current_user():
      greeting.author = users.get_current_user()

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

Esse novo manipulador Guestbook cria um novo objeto de Greeting e configura suas propriedades author e content com os dados postados pelo usuário. Ele não define a propriedade date. Portanto, date é definida automaticamente para "now" (agora), com base na configuração do modelo.

Por fim, greeting.put() salva o novo objeto no armazenamento de dados. Se este objeto foi adquirido em uma consulta, put() deve atualizar o objeto existente. Como criamos este objeto com o construtor de modelo, put() adiciona o novo objeto ao armazenamento de dados.

Recuperação das saudações armazenadas com GQL

O armazenamento de dados do Google App Engine possui um mecanismo de consulta sofisticado para modelos de dados. Como o armazenamento de dados do Google App Engine não é um banco de dados relacional tradicional, as consultas não são especificadas usando SQL. Em vez disso, você pode prepará-las usando uma linguagem de consultas semelhante à SQL, a qual chamamos de GQL. A GQL usa uma sintaxe familiar para fornecer acesso aos recursos do mecanismo de consultas do armazenamento de dados do Google App Engine.

A versão nova do manipulador MainPage mostrada a seguir consulta saudações no armazenamento de dados:

class MainPage(webapp.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')

    greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")

    for greeting in greetings:
      if greeting.author:
        self.response.out.write('<b>%s</b> wrote:' % greeting.author.nickname())
      else:
        self.response.out.write('An anonymous person wrote:')
      self.response.out.write('<blockquote>%s</blockquote>' %
                              cgi.escape(greeting.content))

    # Write the submission form and the footer of the page
    self.response.out.write("""
          <form action="/sign" method="post">
            <div><textarea name="content" rows="3" cols="60"></textarea></div>
            <div><input type="submit" value="Sign Guestbook"></div>
          </form>
        </body>
      </html>""")

A consulta ocorre nesta linha:

    greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")

Você também pode chamar o método gql(...) da classe Greeting e omitir SELECT * FROM Greeting da consulta:

    greetings = Greeting.gql("ORDER BY date DESC LIMIT 10")

Assim como na SQL, as palavras-chave (como SELECT) não fazem distinção entre maiúsculas e minúsculas. Entretanto, os nomes fazem distinção entre maiúsculas e minúsculas.

Como a consulta retorna objetos de dados completos, não faz sentido selecionar propriedades específicas do modelo. Todas as consultas de GQL começam com SELECT * FROM model (ou esse valor é subentendido pelo método gql(...) do modelo), para que fiquem parecidas com seus equivalentes em SQL.

Uma consulta em GQL pode ter uma sentença WHERE para filtrar o conjunto de resultados por uma ou mais condições baseadas em valores de propriedade. Diferentemente da SQL, as consultas em GQL não podem conter constantes de valor. Em vez disso, a GQL usa submissão de parâmetros para todos os valores das consultas. Por exemplo, para obter somente as saudações postadas pelo usuário atual:

    if users.get_current_user():
      greetings = Greeting.gql("WHERE author = :1 ORDER BY date DESC",
                               users.get_current_user())

Você também pode usar parâmetros de nomes em vez de parâmetros de posição:

      greetings = Greeting.gql("WHERE author = :author ORDER BY date DESC",
                               author=users.get_current_user())

Além de GQL, a API de armazenamento de dados fornece outro mecanismo de construção de objetos de consulta usando métodos. A consulta descrita acima também poderia ser preparada conforme mostrado a seguir:

      greetings = Greeting.all()
      greetings.filter("author =", users.get_current_user())
      greetings.order("-date")

Para uma descrição completa da GQL e das APIs de consulta, consulte a Referência de armazenamento de dados.

Limpeza do armazenamento de dados do servidor para desenvolvimento

O servidor da web para desenvolvimento usa uma versão local do armazenamento de dados para testar seu aplicativo, usando arquivos temporários. Os dados persistem enquanto os arquivos temporários existirem, e o servidor da web não restaura esses arquivos a menos que você solicite que ele o faça.

Use a opção --clear_datastore ao iniciar o servidor, se você desejar que o servidor para desenvolvimento apague seu armazenamento de dados antes de ser iniciado:

dev_appserver.py --clear_datastore helloworld/

Próximo passo...

Agora temos um aplicativo de livro de visitas funcional, que autentica os usuários usando contas do Google, permite que enviem mensagens e exibe as mensagens deixadas por outros usuários. Como o Google App Engine realiza as adequações automaticamente, não será necessário rever este código quando nosso aplicativo tornar-se popular.

Esta última versão mistura conteúdo HTML com o código para o manipulador MainPage. Isso dificultará a alteração da aparência do aplicativo, especialmente quando ele se tornar maior e mais complexo. Vamos usar modelos para gerenciar a aparência e introduzir arquivos estáticos para criar uma folha de estilos CSS.

Vá para Uso de modelos.