用Google App Engine写一个留言板程序(一)
分享一下学习Google App Engine的学习心得,整个文章包括以下部分:
·Google App Engine前言介绍
·开发环境配置
·起步,写个Hello, World!进行测试
·App Engine的对象实体,使用Datastore API添加并显示留言内容
·使用Users API,创建用户登录和管理员身份识别,回复留言、删除留言
·让你的程序更健壮,捕捉处理异常和错误
·激动人心的地方,使用模板!
·如何在程序中使用静态文件,如CSS、脚本、图片、视频等。
·将程序上传到Google App Engine的免费测试服务器http://application-id.appspot.com
这是文章的第一部分
前言:什么是Google App Engine?
Google App Engine是一个托管的服务,允许你本地使用Google基础设施构建Web应用,待其完工之后再将其部署到Google基础设施之上(Google的服务器环境)。Google App Engine分为免费版和收费版,免费版提供了一个配额系统,它限制了应用免费可用的存储、CPU和带宽。目前免费版的配额包括:3个应用/开发者、500MB存储/应用、2000封邮件/天(连续24小时)、10 GB入站带宽、10 GB出站带宽、200M CPU兆周、650k HTTP请求、2.5M Datastore API调用和160k URL Fetch API调用。这对我们来说足可以创建一个小型的、学习试验目的程序了。
目前Google App Engine提供的语言支持仅为Python,未来可能会增加更多语言支持(估计短期不太可能)。
Google App Engine SDK可以看作是类似.NET Framework一样的平台(这个比喻不太恰当,但你可以先这样理解),这个环境运行在Google的服务器上,Google对它的安全、性能等作了多种限制和调节。另外Google App Engine是有选择性的支持Python,你不可能用到Python的全部特性。
关于Google App Engine的更多信息可以了解Google推出Web开发利器:AppEngine
开发环境配置(本文描述的系统环境为windows系统):
1、Google App Engine是运行在Python2.5基础上的,如果没有安装Python 2.5,请从Python的官方网站(http://www.python.org/)下载和安装对应操作系统的版本。
2、下载App Engine SDK(http://code.google.com/appengine/downloads.html)。截至写文章之前,SDK的最新版本是1.1,下载后运行安装程序,按照提示操作即可。
3、有两个重要的命令帮助我们处理操作程序
·dev_appserver.py,Web服务器开发
(http://code.google.com/appengine/docs/thedevwebserver.html)
·appcfg.py,用来上传你的程序到App Engine
(http://code.google.com/appengine/docs/appcfgpy.html)
正常安装SDK,Windows安装程序会把这些命令直接放到命令路径中。安装完成SDK之后,你可以直接从命令行窗口下运行这些命令。
起步,写个Hello, World!进行测试
1、创建一个名为helloworld的目录。本程序提到的所有文件都放置在这个目录中。
进入到helloworld目录中,创建一个名为helloworld.py的文本文件,并添加以下代码:
print 'Content-Type: text/plain'
print ''
print 'Hello, world!'
这个Python脚本响应一个请求,这个响应包括描述内容类型的HTTP头、一个空行
以及信息“Hello world!”。
2、创建配置文件
App Engine应用程序有一个名为app.yaml的配置文件。此文件描述了哪个处理器(handler)脚本对应哪个URL。在helloworld目录中,创建一个名为app.yaml的文件,并添加以下内容:
version: 1
runtime: python
api_version: 1
handlers:
- url: /.*
script: helloworld.py
这个文件的语法是YAML(http://www.yaml.org/)。若要查看完整的配置选项列表,请查看app.yaml参考(http://code.google.com/appengine/docs/configuringanapp.html)。
可以把这个文件当成asp.net的web.config文件,主要配置程序一些必要的信息。
3、测试
在桌面点击开始->附件->命令提示符,在命令提示符状态下进入使用下列命令启动Web服务器,路径为helloworld的目录:
dev_appserver.py helloworld/
注意:是目录外,而且目录名不能包含空格
正常情况下,这个Web服务器开始运行,可以监听8080端口的请求。通过在浏览器中访问下面的地址来测试这个程序。http://localhost:8080/,如果一切正常,浏览器中会显示出Hello world!的字样。你可以编辑helloworld.py文件,将Hello, world!替换成其它字符,刷新浏览器即可看到变化。若要关闭Web服务器,在终端窗口激活的情况下,按下Control-C(或Control-Break)。或者直接关掉窗口。
接下来我们开始实现写一个留言板程序
1、创建一个目录,名字为messageboard,创建一个app.yaml文件,添加以下内容:
version: 1
runtime: python
api_version: 1
handlers:
- url: /
script: messageboard.py
2、创建一个messageboard.py,添加以下内容:
import os
import re
import cgi
import datetime
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
# -*- coding: utf-8 -*-是告诉python,这个文件格式为utf-8(保存文件时也要选择保存为utf-8),import语句相当于asp.net 的using,将需要的类库导入到程序中,其中以google.*开头的是Google App Engine SDK里面的库。具体import和from的区别可参考python的文档。
3、继续,创建一个实体类,将以下代码添加至messageboard.py
title=db.StringProperty()
nickname=db.StringProperty()
email=db.EmailProperty()
website=db.LinkProperty()
content=db.StringProperty(multiline=True)
reply=db.StringProperty(multiline=True)
ipaddress=db.StringProperty()
adddate=db.DateTimeProperty(auto_now_add=True)
这个类定义了一个留言信息的Model,诸如留言标题、昵称、电子邮件等属性,其中的db.StringProperty()之类的代码是指定了属性的数据类型,db.StringProperty()代表这个属性是个字符串,db.StringProperty(multiline=True)是一个带有multiline=True参数的db.StringProperty类型,指定属性可以存储多行文本。db.EmailProperty()和db.LinkProperty()是SDK为我们定义好的属性类型,指定属性必须为Email格式和超链接格式,带有auto_now_add=True参数的db.DateTimeProperty类型指定了当对象被创建时,如果应用程序没有赋予其他值,那么新的对象自动被赋予一个date的时间。更多的信息可以参考(http://code.google.com/appengine/docs/datastore/typesandpropertyclasses.html)
4、实现添加留言的功能,将以下代码添加至messageboard.py:
def get(self):
self.response.out.write("""
<form action="/sign" method="post">
<div><input type="text" name="title"/></div>
<div><input type="text" name="nickname"/></div>
<div><input type="text" name="email"/></div>
<div><input type="text" name="website"/></div>
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
</body>
</html>""")
class Add(webapp.RequestHandler):
def post(self):
message = Message()
message.title = self.request.get('title')
message.nickname = self.request.get('nickname')
message.email = self.request.get('email')
message.website = self.request.get('website')
message.content = self.request.get('content')
message.put()
self.redirect('/')
def main():
application = webapp.WSGIApplication([('/', MainPage),('/sign', Add)],debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == "__main__":
main()
这次添加的代码稍多一些,主要是两个类,一个是MainPage用来显示留言的表单,程序是直接将硬代码write到页面了;Add类用来将提交的表单存储到数据库中。message.put()的作用就是保存我们的Message对象到数据库中,并转向到起始页。
还有一个函数main用来接受请求并指定请求匹配的处理器(这里指的就是MainPage类和Add类),例如,当webapp接收到一个HTTP GET对URL“/”的请求时,它会实例化MainPage类,并调用这个实例的get方法。参数debug=true可以捕捉错误或异常并且显示出来。
应用程序本身由webapp.WSGIApplication实例来呈现,代码使用了来自Python标准库的wsgiref模块来运行WSGIApplication,即一个CGI适应器。想要了解这个模块更多的信息,请访问wsgiref模块文档(http://docs.python.org/lib/module-wsgiref.html)。了解webapp的更多信息,请查看webapp参考(http://code.google.com/appengine/docs/webapp/)。
5、接下来我们再修改一下app.yaml文件
version: 1
runtime: python
api_version: 1
handlers:
- url: /
script: messageboard.py
- url: /add
script: messageboard.py
现在就可以运行dev_appserver.py messageboard/ 进行调试了。在浏览器中输入http://localhost:8080/,可以看到留言表单,输入一些内容测试。点击提交按钮并没有出现什么变化,实际上数据已经存储了。开发Web服务器使用一个本地版本的数据库来测试你的应用程序,即使用临时文件。只要临时文件错在数据就会一直存在,Web服务器不会重置这些文件
除非你要求这么做。如果你想要开发服务器在启动时预先清除数据库,请在启动服务器时添加--clear_datastore选项:
dev_appserver.py --clear_datastore messageboard
6、那么,如何将存储的数据显示出来呢?修改你的MainPage类如下:
def get(self):
messages = db.GqlQuery("SELECT * FROM Message ORDER BY adddate DESC LIMIT 10")
for message in messages:
self.response.out.write('%s于%s留言:'%(message.nickname,message.adddate))
self.response.out.write('<hr/>邮件:%s<br/>网址:%s<br/>留言内容:<blockquote>%s</blockquote>' %(message.email,message.website,cgi.escape(message.content)))
self.response.out.write("""
<form action="/add" method="post">
<div>标题:<input type="text" name="title"/></div>
<div>昵称:<input type="text" name="nickname"/></div>
<div>邮件:<input type="text" name="email"/></div>
<div>网址:<input type="text" name="website"/></div>
<div>内容:<textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="提交"></div>
</form>
</body>
</html>""")
看看这句messages = db.GqlQuery("SELECT * FROM Message ORDER BY adddate DESC LIMIT 10"),Google App Engine使用与sql语句相似的称为gql的语句进行数据库查询,这个查询返回添加的信息的Message对象模型。接下来
for message in messages:
self.response.out.write('%s于%s留言:'%(message.nickname,message.adddate))
self.response.out.write('<hr/>邮件:%s<br/>网址:%s<br/>留言内容:<blockquote>%s</blockquote>' %(message.email,message.website,cgi.escape(message.content)))
用于遍历这个messages对象集合,并将内容write出来。。
GQL和SQL相似度较高,其中GQL增加了一些特殊语法,已适应App Engine的环境,查看完整的GQL及查询API描述,请参见数据存储参考(http://code.google.com/appengine/docs/datastore/)。
调试一下我们的程序,如果测试服务器没有关闭的话,刷新一下浏览器中(http://localhost:8080/)即可看到刚刚提交的留言,你可以尝试继续提交留言并查看变化。
注意,当填写的Email和Url不符合标准的话,测试服务器会捕捉到错误并显示出来,例如:BadValueError: Invalid URL: ww.124.cm 说明添加的网址格式错误,我们可以根据此机制来编写处理代码,让我们的程序更健壮、更安全。
通过以上的学习,初步构建了一个可以运行在本地App Engine环境的程序,当然,它还很稚嫩,程序不健壮、界面不友好,没有区分用户身份,无法对存储数据管理等等。下篇文章将帮你解决这些问题,下篇文章预告:
- ·使用Users API,创建用户登录和管理员身份识别,回复留言、删除留言
·让你的程序更健壮,捕捉处理异常和错误
·激动人心的地方,使用模板!
·如何在程序中使用静态文件,如CSS、脚本、图片、视频等。
·将程序上传到Google App Engine的免费测试服务器http://application-id.appspot.com