Google App Engine 入门:数据存储
数据存储是个复杂的问题。用户可能在一个特定的时间发出了一个数据请求,但是下一个时间又发出了另外一个完全不同的数据请求。所有的WEB服务都需要协调这些相互影响的请求,并且这些请求可能来自世界的各个地方。
感谢Google App Engine,您再也不需要为这些发愁了。Google App Engine架构将为您处理所有关于数据分发,负载平衡的问题,并且提供了API来实现所有关于数据存储的问题。
存储已经提交的留言
App Engine 包含了一个基于Python的数据存储模型. 这个模型类似于 Django’s data modelling API, 但是使用了Google自己的存储环境.
对于上一章实现的留言程序,我们想要把用户提交的留言保存起来,每个留言都包含作者名称,消息内容,发布时间等等,并且按照留言的先后将其显示出来。
编辑 helloworld/helloworld.py, 在顶部添加 import代码 :
from google.appengine.ext import db
添加 Greeting类:
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
上面的代码定义了一个数据模型类Greeting,这个类包含三个属性: author -User object类型, content - 字符串类型, date -日期类型.
其中一些属性包含了默认值:比如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 处理过程创建了一个Greeting 对象,设置了它的属性,然后使用 greeting.put()方法把它保存了起来。如果对象已经存在,使用put()方法,将会更新原先已经存在的数据。在这段代码里,我们是直接创建了Greeting对象,所以put()方法将把一个新的Greeting对象保存起来。
通过GQL查询数据
App Engine datastore 使用了一套复杂的数据储存系统.但是它并不是一个标准的关系数据库,所以不能使用标准的Sql语句进行查询。作为一个替代,Google准备了一套类Sql的查询语句,称之为GQL.GQL 提供了和SQL基本类似的语法来读取数据.
编辑MainPage :
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>""")
刷新http://localhost:8080/ , 您可以提交一个留言看一下效果.
以下是相关的查询语句:
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/
接下来…
现在我们已经创建一个一个完整的留言板,但是这个版本中的HTML代码都包含在MainPage处理过程中,如果我们想要修改一下WEB应用的外观,将是一件麻烦的事情,接下来我们将学习如何使用模板,添加图片,CSS等静态文件。
下一章 使用模板.

2008-05-10 12:10
[…] 下一章 使用数据存储. […]
2008-06-13 10:04
使用数据存储和使用模板这两节的代码有问题,我调试不过。能不能把你这两节的代码发给我?谢谢
2008-06-13 10:05
使用数据存储和使用模板这两节的代码有问题,我调试不过。能不能把你这两节的代码发给我?谢谢
我的email:yongjiang@163.com
2008-06-13 23:32
回楼上,需要严格的缩进。
2008-06-13 23:50
import cgi
import wsgiref.handlers
from google.appengine.api import users
from google.appengine.ext import webapp
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(”)
greetings = Greeting.gql(”ORDER BY date DESC LIMIT 10″)
for greeting in greetings:
if greeting.author:
self.response.out.write(’%s wrote:’ % greeting.author.nickname())
else:
self.response.out.write(’An anonymous person wrote:’)
self.response.out.write(’
‘ %
cgi.escape(greeting.content))
# Write the submission form and the footer of the page
self.response.out.write(”"”
“”")
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(’/')
def main():
application = webapp.WSGIApplication(
[(’/', MainPage),
(’/sign’, Guestbook)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == “__main__”:
main()
帮忙看看?
2008-06-14 00:03
Traceback (most recent call last):
File “/base/python_lib/versions/1/google/appengine/ext/webapp/__init__.py”, line 499, in __call__
handler.get(*groups)
File “/base/data/home/apps/kin/1.14/kin.py”, line 28, in get
for greeting in greetings:
File “/base/python_lib/versions/1/google/appengine/ext/db/__init__.py”, line 1247, in __iter__
return self.run()
File “/base/python_lib/versions/1/google/appengine/ext/db/__init__.py”, line 1558, in run
query_run = self._proto_query.Run(*self._args, **self._kwds)
File “/base/python_lib/versions/1/google/appengine/ext/gql/__init__.py”, line 441, in Run
res = bind_results.Get(self.__limit, offset)
File “/base/python_lib/versions/1/google/appengine/api/datastore.py”, line 928, in Get
return self._Run(limit, offset)._Next(limit)
File “/base/python_lib/versions/1/google/appengine/api/datastore.py”, line 877, in _Run
str(exc) + ‘\nThis query needs this index:\n’ + yaml)
NeedIndexError: no matching index found
This query needs this index:
- kind: Greeting
properties:
- name: date
direction: desc
2008-06-14 05:18
http://localhost:8080/ 可以用,但是appspot.com不能用
2008-06-14 10:11
好像第一次访问的时候会有这个问题,可能是datastore还没有创建好,刷新一下就好了。