2008年11月23日星期日

[转载]Google App Engine入门指南

译文原始出处不可考。保留译者信息。

原文网址:
http://code.google.com/appengine/docs/gettingstarted/
翻译者:
otherrrr@gmail.com

(注:转载请告知我一声,谢谢!)

(注:在我翻译的同时,版本从1.0.0升到了1.0.1,
我还没有发现文字有什么变化,但是有可能有些许不同)

入门指南

本教程描述了如何使用Google App Engine开发和部署一个简单的项目。
作为案例项目的"用户留言簿"演示如何使用各种App Engine服务,
这些服务包括数据存储和Google用户服务。

本教程包括下列部分:
・介绍
・开发环境
・Hello, World!(译注:这个不用翻译吧)
・使用webapp框架
・使用用户服务
・使用webapp处理表单
・使用数据存储
・使用模板
・使用静态文件
・上传你的程序

(译注:小节名会用"#"来标注,小小节名会用"##"来标注)
# 介绍

欢迎使用Google App Engine!创建一个App Engine程序非常容易,
而且只需要花费很少的时间。它是免费的,只需要上传你的程序,
马上就能和使用者来分享,不需要任何费用和许可。

在本教程中,会创建一个简单的用户留言簿程序,可以让用户发表
信息到一个公共的信息版。用户可以匿名发表,也可以使用他们的
Google帐户。

用户留言簿程序会演示如何使用App Engine数据仓库,如何将App
Engine程序和Google帐户结合起来,以及演示如何使用一个简单的
Python Web框架。这个Web框架已经包含在App Engine中,即:webapp。
这个程序也会演示如何使用Django模板引擎。
(译注:原文在每个小节之后会有一个"Next",有些承上启下的文字,未译)

# 开发环境

使用Google App Engine开发和上传程序需要用到App Engine软件开发包(SDK)。

SDK包括Web服务器程序,该程序用来模仿App Engine环境,包含一个本地的数据库、
Google帐户以及获取URL的能力和使用App Engine API来从你的电脑上直接发送Email。
SDK可以运行在任何安装Python 2.5的电脑上,提供的版本包括Windows、Mac OS X和
Linux。
(译注:不知道是不是应该把App Engine翻译成程序引擎?)

如果没有安装Python 2.5,请从Python的官方网站(http://www.python.org/)下载
和安装对应操作系统的版本。Mac OS X 10.5 Leopard用户已经直接安装了Python 2.5。

下载App Engine SDK(http://code.google.com/appengine/downloads.html)。
按照下载页面的提示来安装SDK到你的电脑上。

对于本教程来说,你会使用到SDK中的两个命令:

・dev_appserver.py,Web服务器开发
http://code.google.com/appengine/docs/thedevwebserver.html
・appcfg.py,用来上传你的程序到App Engine
http://code.google.com/appengine/docs/appcfgpy.html

Windows和Mac OS X安装程序会把这些命令直接放到命令路径中。
安装完成之后,你可以直接从命令行窗口下运行这些命令。
(译注:在Windows下是命令提示符)

如果你使用SDK的Zip文档版本,你会在google_appengine目录下发现这些命令。

# Hello, World!
Google App Engine程序和Web服务器之间使用CGI标准进行交互。
(查看CGI标准:http://hoohoo.ncsa.uiuc.edu/cgi/interface.html
当服务器收到你的程序的一个请求时,它使用请求的数据来运行程序
并处理标准输入流(对于POST数据来说)。作为相应,应用程序写响应到标准
输出流中,包括HTTP头和内容。
(译注:这一段翻译的不好)

让我们来实现一个小小的程序:显示一段信息。

## 创建一个简单的请求处理器

创建一个名为helloworld的目录。本程序的所有文件都放置在这个目录中。

进入到helloworld目录中,创建一个名为helloworld.py的文件,并添加如下代码:

print 'Content-Type: text/plain'
print ''
print 'Hello, world!'

这个Python脚本响应一个请求,这个响应包括描述内容类型的HTTP头、一个空行
以及信息"Hello world!"。

## 创建配置文件

App Engine应用程序有一个名为app.yaml的配置文件。
此文件描述了哪个处理器(handler)脚本对应哪个URL。

在helloworld目录中,创建一个名为app.yaml的文件,并添加如下内容:

application:helloworld
version:1
runtime:python
api_version:1

handlers:
- url:/.*
script:helloworld.py

从上至下,配置文件依次说明了关于程序的下列信息:
・应用程序的标识符是"helloworld"。当你使用App Engine注册你的应用程序时,
在最后一步你会选择一个唯一的标识符,并更新这个值。这个值在开发阶段
可以是任意值。从现在开始,将它设置为"helloworld"。
・版本号"1"是这个应用程序的编号。如果程序更新到了新的版本,App Engine会
保留前面的版本,可以用管理控制台回溯至前面的版本。
・这个代码运行在"python"运行环境下。不久的将来会支持其他运行环境和语言。
・每一个对URL的请求的路径会匹配正则表达式"/.*"(这个正则表达式表示所有的
URL),这将会由"helloworld.py"脚本来处理。
(译注:上面的小节中引号部分在原文中均为绿色,指代上上小节中的代码)
(译注:第一行application后面不能加"_",比如"hello_world"就不行)

这个文件的语法是YAML
http://www.yaml.org/)。
若要查看完整的配置选项列表,请查看app.yaml参考
http://code.google.com/appengine/docs/configuringanapp.html)。

## 测试应用程序
使用处理器脚本和配置文件会将每个URL映射至处理器,这样程序就算是完成了。
现在你可以使用App Engine SDK中包含的Web服务器来测试这个程序了。

使用下列命令启动Web服务器,路径为helloworld的目录:

google_appengine/dev_appserver.py helloworld/
(译注:注意目录名不能包含空格,比如放置在桌面就不行)
(译注:我是在google_appengine目录下,输入:python dev_appserver.py hellworld,
然后问是否更新,我看到最新版本是1.0.1了,但是我这里因为网络问题更新不了)

这个Web服务器开始运行,可以监听8080端口的请求。
通过在浏览器中访问下面的地址来测试这个程序。

http://localhost:8080/

想要了解更多关于运行开发Web服务器的信息,包括如何修改使用的端口,
请查看Dev Web服务器参考
http://code.google.com/appengine/docs/thedevwebserver.html),
或者运行命令时附加选项:--help。

## 迭代开发

你可以在开发程序的过程中保持Web服务器一直在运行。
Web服务器会监视源程序的变化,并在适当的时候重载它们。

试一下:保持Web服务器在运行中,编辑helloworld.py文件,将其中的Hello, world!
改为其他语句。刷新http://localhost:8080/就可以看到变化。

若要关闭Web服务器,在终端窗口激活的情况下,按下Control-C
(或Control-Break)。

你可以保持Web服务器一直运行,因为教程的后面还会用到。
如果你需要停止它,你可以重启它通过运行上面的命令。

# 使用webapp框架

CGI标准非常简单,但是手写全部的代码还是非常笨重的。
Web应用程序框架就会替你处理这些细节,这样你就可以只关注于你的应用程序功能。
Google App Engine支持任何使用纯Python编写的支持CGI的框架
(以及任何使用CGI适配器的WSGI框架),包括Django、CherryPy、Pylons和web.py。
你可以选择你的程序代码绑定到一个框架,只需要将代码复制到程序目录中。
(WSGI:http://www.python.org/dev/peps/pep-0333/
(Django:http://www.djangoproject.com/
(CherryPy:http://www.cherrypy.org/
(Pylons:http://pylonshq.com/
(web.py:http://webpy.org/

App Engine包括一个简单的Web程序框架,名为:webapp。
webapp框架已经安装在App Engine环境和SDK中,所以你不需要绑定它,
可以直接在应用程序代码中使用。在教程的后续部分中,我们会使用webapp。

## Hello, webapp!

一个webapp应用程序由三个部分组成:
・一个或多RequestHandler类,用来处理请求和创建响应
・一个WSGIApplication实例,用来将输入请求连到基于URL的处理器
・使用CGI适应器运行WSGIApplication的主程序

让我们重新写我们的"友好的问候"(译注:这里指Hello world,幽默一下),
作为一个webapp程序。
编辑Helloworld/helloworld.py,并用下面的内容来进行替换:

import wsgiref.handlers

from google.appengine.ext import webapp

class MainPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')

def main():
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
main()
(译注:我第一次看有人用两个空格作为缩进)

在浏览器中刷新http://localhost:8080/,可以看到新版本的运行结果。
(如果你已经停止了你的Web服务器,请重新启动它,
具体的命令在"Hello, World!"章节中有介绍)

## webapp做了什么

webapp模块在google.appengine.ext包中。
这个模块在SDK中提供,也在生产运行环境中。

代码定义了一个请求处理器"MainPage",并映射到根URL(/)。
当webapp接收到一个HTTP GET对URL"/"的请求时,它会实例化MainPage类,
并调用这个实例的get方法。在这个方法中,关于请求的信息可以被self.request
所调用。例如:这个方法为每个响应来设置self.response的变量,然后退出。
webapp在MainPage实例的最后阶段发送一个响应。

应用程序本身由webapp.WSGIApplication实例来呈现。
参数debug=true传递到构造器,通知webapp打印出浏览器输出的栈跟踪,
当然前提是如果处理器遇到错误或引发一个为捕捉的异常。
在你的程序的最终版本中,你会去除这个选项。

代码使用了来自Python标准库的wsgiref模块来运行WSGIApplication,即一个
CGI适应器。想要了解这个模块更多的信息,请访问wsgiref模块文档
http://docs.python.org/lib/module-wsgiref.html)。

在本教程的后面我们会用到webapp的一些其他功能。
想要了解webapp的更多信息,请查看webapp参考
http://code.google.com/appengine/docs/webapp/)。

# 使用用户服务

Google App Engine提供很多有用的服务,这些服务都基于Google基础构造,
(注:我将infrastructure翻译为基础构造,
但是我理解的是Google的一些基础服务及文件)
可以通过SDK中包含的库来使得程序可以访问这些服务。
其中的一个服务就是用户(User)服务,这个服务可以使你的程序和
Google用户帐户进行整合。
使用用户服务,你的用户可以使用他们已有的Google帐户来申请你的应用。

让我们看看用户服务是如何定制应用程序的个性化问候。

## 使用用户(Users)

再次编辑helloworld/helloworld.py,
使用下面的内容进行替换:

import wsgiref.handlers

from google.appengine.api import users
from google.appengine.ext import webapp

class MainPage(webapp.RequestHandler):
def get(self):
user = users.get_current_user()

if user:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, ' + user.nickname())
else:
self.redirect(users.create_login_url(self.request.uri))

def main():
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
main()

在浏览器中重新加载页面。
你的程序会重定向到一个本地版本的Google登陆页面,
这个页面可以用来测试你的程序。
你可以在屏幕上输入任何你喜欢的用户名,
然后你的程序会发现一个基于这个用户名的伪造User对象。

当你的程序运行在App Engine上时,用户会被导向到Google帐户
的登陆页面,当登陆之后,或注册了一个新帐户之后,
会重新返回到你的应用。

## Users API

让我们来仔细研究一下新的代码:

user = users.get_current_user()

如果用户已经注册了你的应用,get_current_user()返回用户的
User对象。如果没有,那么返回None。

if user:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, ' + user.nickname())

如果用户已经登陆,显示一个个性化的信息,使用和用户帐户
相关的昵称。

else:
self.redirect(users.create_login_url(self.request.uri))

如果用户没有登陆,告诉webapp重定向用户的浏览器至Google帐户登陆页面。
重定向中包含此页的网址(self.request.uri),这样Google帐户登陆机制
才能在用户登陆完成或注册完成之后将用户返回来。

想要了解更多Users API的信息,请参见用户参考
http://code.google.com/appengine/docs/users/)。

# 使用webapp处理表单

如果你想要用户提交他们自己的问候,我们就需要一个方法来处理
用户通过Web表格提供的信息。
webapp框架使得处理表格数据变得更容易。

## 使用webapp处理Web表格

使用下列内容替换helloworld/helloworld.py中的内容:

import cgi
import wsgiref.handlers

from google.appengine.api import users
from google.appengine.ext import webapp

class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write("""
<html>
<body>
<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):
self.response.out.write('<html><body>You wrote:<pre>')
self.response.out.write(cgi.escape(self.request.get('content')))
self.response.out.write('</pre></body></html>')

def main():
application = webapp.WSGIApplication(
[('/', MainPage),
('/sign', Guestbook)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
main()

刷新页面就可看到此表格,然后试着提交一条信息。

当前版本有两个处理器(handler):
MainPage,映射到地址"/",显示一个Web表格。
Guestbook,映射到地址"/sign",显示Web表格提交的数据。

Guestbook处理器有一个post()方法,而没有get()方法。
这是因为MainPage显示的表格使用了HTTP POST方法(method="post")
来提交表格数据。
如果因为某些原因你想要一个处理器可以对同一个网址进行GET和POST
操作,你可以在相同类中为每个动作定义这样一个方法。

post()方法中的代码获取来自self.request的表格信息。
在显示给用户之前,它使用cgi.escape()来将HTML特定字符转换成
这些字符的对应体。cgi是一个标准的Python库;查看cgi文档来获取
更多信息(http://docs.python.org/lib/module-cgi.html)。

注意:App Engine环境包含完整的Python 2.5标准库。
但是,不是所有的操作都被允许。
App Engine程序运行在一个受限的环境中,
只能允许App Engine安全的进行扩展。
例如:对操作系统的低层调用、网络操作以及一些文件系统操作
都是不允许的,当尝试这些操作时,会引起错误。
了解更多信息,查看Python运行环境
http://code.google.com/appengine/docs/python/)。

# 使用数据存储

在可扩展的Web应用程序中,存储数据是非常困难的。
用户在某段时间中会和多个Web服务器进行交流,
用户的上一个请求是这个服务器进行处理的,
但是下一个请求会跳至其他的服务器。
所有的Web服务器会对数据进行沟通,
这也许会扩展到数十个服务器,
这些服务器有可能在不同的地方。

但是依靠Google App Engine,你不用过多考虑上述的问题。
App Engine的架构考虑到了数据的所有发布、分派和加载平衡,
这些都在一个简单API后面,
这就是一个强大的查询和处理引擎。

## 保存提交的问候

App Engine包括Python的数据模型API(data modelling API)。
它和Django的数据模型API比较相似
http://www.djangoproject.com/documentation/model-api/)。
但是在后端使用了App Engine的可扩展数据存储。

对于留言簿应用程序来说,我们想要去存储用户提交的问候语。
每个问候语包括作者的名字、信息的内容以及信息提交的日期和时间,
日期和时间能确保我们按照时间顺序来显示这些信息。

编辑helloworld/helloworld.py文件,
并在顶部添加下列import语句:

from google.appengine.ext import db

在MainPage类上面添加下面这个类:

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

这个类定义了Greeting模型,该模型有3个属性:
author,值为User对象
content,值为一个字符串
date,值为datetime.datetime
(译注:datetime请参考python说明,import datetime; help(datetime))

带有参数的属性构造器可以进一步指定它们的行为。
带有multiline=True参数的db.StringProperty构造器
标明这个值可以包含多行字符。
带有auto_now_add=True参数的db.DateTimeProperty构造器
指定了当对象被创建时,如果应用程序没有赋予其他值,
那么新的对象自动被赋予一个date的时间。
查看万张的属性类型和选项列表,查看数据存储参考
http://code.google.com/appengine/docs/datastore/)。

现在我们有了一个问候语的数据模型,应用程序可以用这个模型
来创建一个新的Greeting对象,并将它们存进数据库中。
编辑Guestbook处理器,代码如下:

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对象,并将用户提交
的数据来设置了它的author和content属性。
如果没有设置date属性,那么date会被自动设置为"now"(当前),
就像我们在模型中制定的那样。

最后,greeting.put()保存我们的新对象到数据库中。
如果我们获取到对象的查询,put()会坑新当前对象。
因为我们使用模型构造器来创建对象,
因此put()创建了一个新的对象到数据库中。

## 使用GQL找回存储的问候语

App Engine数据库有一个优秀的(sophisticated)的数据模型
查询引擎。因为App Engine数据库不是传统关系数据库,因此查询
不是用SQL来定义的。但是你可以使用一种类似SQL的查询语言,
我们称之为GQL。GQL提供了访问App Engine数据库的查询引擎功能,
语法与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")
(译注:我看不出来这和SQL有什么区别)

另外,你也可以调用Greeting类的gql(...)方法,
省略查询中的"SELECT * FROM Greeting":

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

和SQL一样,关键词(例如"SELECT")是大小写不敏感的。
但是,其他变量名是大小写敏感的。
(译注:我感觉把SQL的关键词都大写是一种很好的习惯)

因为查询返回全部数据对象,因此选择模型的特定属性没有什么意义。
所有的GQL查询都是以"SELECT * FROM model"开头,
(或应用模型的gql方法),
或者与之类似的SQL等效语句。
(译注:我其实发现了把model翻译成模型不是太合适,或者是模组?)

(译注:其实greeting翻译成祝福语也挺不准确的,问候语?)
一个有WHERE语句的GQL查询会依据一个或几个条件的属性值来过滤得到的结果。
和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())

除GQL之外,数据存储API提供了使用方法创建查询对象的其他机制。
上面的查询也可以修改为下面的代码:

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

查看完整的GQL及查询API描述,请参见数据存储参考
http://code.google.com/appengine/docs/datastore/)。

## 清除开发服务器数据库

开发Web服务器使用一个本地版本的数据库来测试你的应用程序,
即使用临时文件。
只要临时文件错在数据就会一直存在,Web服务器不会重置这些文件
除非你要求这么做。

如果你想要开发服务器在启动时预先清除数据库,请在启动服务器时
添加--clear_datastore选项:

dev_appserver.py --clear_datastore helloworld/

(注:我最近在找工作,但是找不到。对不起,这和本文没什么关系,sorry)

# 使用模板

代码嵌套在HTML中是很杂乱和难以维护的,最好的办法是使用模板系统。
在模板系统中,HTML被作为一个单独的文件,
使用得定的语法来表明程序中的数据从何而来。
有很多Python的模板系统:EZT、Cheetah、ClearSliver、Quixote和Django等等。
你可以使用你的模板引擎,并将它绑定到你的应用程序代码中。
(EZT:http://svn.webdav.org/repos/projects/ezt/trunk/ezt.py
(Cheetah:http://www.cheetahtemplate.org/
(ClearSliver:http://www.clearsilver.net/
(Quixote:http://www.mems-exchange.org/software/quixote/
(Django:http://www.djangoproject.com/documentation/templates/

为了更加方便,webapp模块包含了Django模板引擎。这也作为一个部分包含在
SDK和App Engine中,所以你使用的时候不需要再去绑定它。

## 使用Django模板

添加下列import语句在helloworld/helloworld.py的顶部:

import os
from google.appengine.ext.webapp import template

使用下面代码替换MainPage处理器:

class MainPage(webapp.RequestHandler):
def get(self):
greetings = Greeting.all().order('-date')

if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'

template_values = {
'greetings': greetings,
'url': url,
'url_linktext': url_linktext,
}

path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))

最后在helloworld目录中创建一个index.html文件,该文件的内容如下:

<html>
<body>
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author.nickname }}</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}

<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>

<a href="{{ url }}">{{ url_linktext }}</a>

</body>
</html>

刷新一下页面,然后看看。

template.render(path, template_values)有两个参数:一个是模板文件的文件路径;
一个是字典值。并返回递归文本。这个模板用了Django模板语法来访问和重申值,
以及来引用这些值的属性。在许多情况下,你可以将数据存储模板对象直接作为值,
并通过模板来访问他们的属性。

提示:一个App Engine应用程序有对这个项目所有上传文件、库文件的只读权限,
但是不包括其他文件。当前工作路径就是程序的主目录,所有index.html
的路径就是简单的"index.html"。

想要了解更多关于Django模板引擎的信息,请访问Django 0.96模板文档
http://www.djangoproject.com/documentation/0.96/templates/)。

# 使用静态文件

和传统的Web主机环境不同,Google App Engine不支持直接访问你的
应用程序源代码目录下的文件,除非制定这样做。我们将我们的模板
文件命名为index.html,但是不会自动使得文件可以通过URL/index.html
来访问。

当时,有很多情况下你希望直接通过Web浏览器访问静态文件。
例如:图片、CSS文件、JavaScript代码、影片和Flash动画就会保存在应用
程序目录下并直接通过浏览器访问。你可以告知App Engine来直接访问特定
的文件,而不需要编辑处理器。

## 使用静态文件

编辑helloworld/app.yaml,并用下列内容进行替换:

application: helloworld
version: 1
runtime: python
api_version: 1

handlers:
- url: /stylesheets
static_dir: stylesheets

- url: /.*
script: helloworld.py

新的hanlers部分定义了两个用于URL的处理器。
当App Engine接收到一个来自网址头部包含/stylesheets的请求时,
它映射文件的剩余路径到stylesheets路径,如果找到对应的文件,
该文件的内容会被返回到客户端。其他网址映射"/"路径,并由
helloworld.py脚本来处理。

默认情况下,App Engine使用基于文件名扩展的MIME类型来访问静态文件。
例如一个文件名后缀为.csss的会被认为是text/css MIME类型。
你可以通过额外的选项来制定准确的MIME类型。

URL处理期路径参数会按照它们在app.yaml中的顺序从顶到底进行处理。
在本例中,/stylesheets参数会在/.*参数映射之前找到相应路径。
想了解更多URL映射的信息,以及可以制定app.yaml的参数信息,
请查看app.yaml参考(http://code.google.com/appengine/docs/configuringanapp.html)。

创建目录helloworld/stylesheets。
在这个新目录中,创建一个新文件,名为main.css,内容如下:

#body {
# font-family: Verdana, Helvetica, sans-serif;
# background-color: #DDDDDD;
#}
(注:css内容前面每一行我都加了"#"以免显示不正确)
(注:在支持文字定义的blog中,css代码都不能正常显示)
otherrrr@gmail.com

最后,编辑helloworld/index.html文件,并插入下面的代码,
在<html>行之后:

# <head>
# <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
# </head>
(注:每一行我都加了一个"#")

在浏览器中刷新页面,会看到使用层叠演示表的新的页面。

# 上传你的程序

你可以使用管理控制台来创建和管理App Engine的应用程序。
如果你注册了你的应用程序ID,你可以使用SDK中的命令行工具
来上传程序到网站上。这个工具是appcfg.py。

注意:在写本文时,还没有办法来删除App Enginge上的程序。
这个功能会很快添加。在预览版本中,你可以注册3个程序ID。
如果你不想为本教程分配一个程序ID,你可只是简单看看这个
部分,当你准备上传程序时在详细的了解。

## 注册应用程序

你可以通过App Engine管理平台创建和管理App Enginge的Web应用程序,
网址如下:
http://appengine.google.com

通过你的Google帐户登陆App Engine。
如果你没有Google帐户,请可以通过一个E-mail地址和密码来创建一个
Google帐户(https://www.google.com/accounts/)。

单击"Create an Applicatio"按钮来创建一个新的应用u程序。
根据指引来注册一个应用程序ID,即这个程序的唯一的名称。
如果你选择使用免费的appspot.com域名,那么这个程序的完整网址
就是:http://application-id.appspot.com/
你可以为你的应用购买一个顶级域名,也可以使用已经注册的域名。

编辑app.yaml文件,然后修改application的对应值:设置helloworld对应
你注册的应用程序ID。
(注:我发现很多人都是因为这个问题结果上传后出错或无法浏览)

## 上传程序

使用下列命令上传完成的应用程序到Google App Engine:

appcfg.py update helloworld/

在命令行(或终端)下输入你的Google用户名和密码。

现在你就可以看到你的程序已经运行在App Enginge上了。
如果你设置使用免费的appspot域名,
那么网址会是:

http://application-id.appspot.com

## 祝贺你!
你已经完成了本教程。
想要了解更多的信息,请参看App Engine文档。
http://code.google.com/appengine/docs/

otherrrr@gmail.com翻译)
--
郎啊郎别太忙 | langalang.blogspot.com

2 条评论: