App Engine中文教程

使用数据库存储|中文版Google App Engine入门指南

对于一个数据量大的网站应用来说数据存储是个很有技巧的的事情。用户可能在一个特定的时间发出了一个数据请求,但是下一个时间又发出了另外一个完全不同的数据请求。所有的WEB服务都需要协调这些相互影响的请求,并且这些请求可能来自世界的各个地方。

由于有了Google App Engine,你再也不需要为这些发愁了。Google App Engine架构将为提供分布式的数据处理,解决负载平衡的问题,并且提供了API来实现所有关于数据存储的问题。

数据存储完整实例

下面是一个最新版的 helloworld/helloworld.py 代码,用来存储用户的留言。下面的所有文字都是用来解释这段代码的。

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

将上面的代码替换掉 helloworld/helloworld.py 原有的代码,然后重新加载 http://localhost:8080/ 试着发布一条留言,看看你的留言是否被正确地存储并且正常地显示了。

存储用户提交的留言

App Engine 包含了一个基于Python的数据存储模型. 这个模型类似于 Django's data modelling API, 但是使用了Google自己的存储环境.

对于上一章实现的留言程序,我们想要把用户提交的留言保存起来,每个留言都包含作者名称,消息内容,发布时间等等,并且按照留言的先后将其显示出来。

为了使用data modeling API,在代码顶部添加 google.appengine.ext.db 模块:

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)

这段代码定义了 Greeting 模型的三个属性: author 是一个 User 对象, content 是一个字符串对象,anddate 是一个datetime.datetime对象。

其中一些属性包含了默认值:比如db.StringProperty 类型中 multiline=True 表明该字符串中可以包含换行符;db.DateTimeProperty类型中 auto_now_add=True 表明当Greeting对象创建的时候,将使用当前时间初始化这个属性。关于数据模型的属性的更多帮助,请查看 the Datastore reference

既然我们已经定义了一个数据对象模型,接下来,我们创建一个Greeting对象,并且把它保存起来。编辑 Guestbook handler :

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

这个新的 Guestbook handler 创建了一个新的 Greeting 对象,然后根据用户提交的数据设置 author 和 content 的属性值。 它并没有甚至 date 的值,所以 date 会自动设成当前时间,因为我们在模型建立的时候已经设置了。

最后一行, greeting.put() 将新创建的对象保存进数据库,如果put()进去的是从数据库中提取的对象,put() 会更新那条数据记录,而现在我们是新创建的一个对象,所以 put() 会添加一条新的记录到数据存储里。

使用 GQL 获取数据记录

App Engine datastore 使用了一套复杂的数据储存系统.但是它并不是一个标准的关系数据库,所以不能使用标准的Sql语句进行查询。作为一个替代,Google准备了一套类Sql的查询语句,称之为GQL.GQL 提供了和SQL基本类似的语法来读取数据。

下面是新版的 MainPage handler 代码,用来查询数据库中的所有留言。

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

查询语句出现在这一行:

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

或者,你也可以在Greeting类里面调用 gql(...) 方法,那样就不必使用 SELECT * FROM Greeting 这样的查询语句了:

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

和SQL语句类似,关键字 (比如 SELECT) 是大小写无视的,字段名是区分大小写的。

要注意的是,GQL语句总是返回完整的对象,所以GQL查询语句不能指定要查询的字段名。也就是说,所有的GQL语句都是以SELECT * FROM model 开头的。

一个GQL查询语句可以用 WHERE指定查询条件,你可以指定一个或多个条件。 和SQL不同的是,GQL查询能包含变量值:GQL使用参数绑定查询中所有的变量.例如 , 获取当前登录用户的留言:

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

你也可以使用命名参数代替之:

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

另外, Google datastore API 还提供了另外一种获取数据的方法::

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

想了解 GQL查询语法的更多内容, 请查看 the Datastore reference

清空开发版服务器中的数据存储

为了方便你测试自己的应用,GAE开发环境使用了一个临时文件来保存本地的数据,要清空本地开发环境的数据,可以使用如下的命令行:

dev_appserver.py --clear_datastore helloworld/

上一页 下一页 

如果大家对于教程里的内容有疑问,或是想要参加到教程的编写工作中,欢迎访问:

康爷的博客