安装
要完成整个教程,你需要安装web.py, flup, Cheetah, psycopg2 和 Postgres。 更多安装方面的细节请见web.py主页.
URL处理
在你的编辑器中打开一个新文件,取名code.py
。输入以下代码:
import web
这会导入web.py框架。
urls = (
'/', 'view'
)
这是URL到函数的映射列表。第一部分是一个正则表达式,它用来匹配一个路径,例如如/
, /help/faq
, /item/(/d+)
, 等等。 (代码 /d+
匹配的是数字串。括号表示保留匹配上的这部分内容留做以后使用。)第二部分是接收请求的类的名称,例如 view
,welcomes.hello
(表示 welcomes
模块的 hello
类), 或 get_/1
。 /1
被替换为正则表达式所保留的第一部分内容;其他保留的匹配内容被传递给函数。
class view:
def GET(self):
这是hello类和它的GET函数。可能你已经猜到了,当有人调用HTTP GET方法时GET函数就会被调用(即有人访问你的URL时)。
print "Hello, world!"
这会返回纯文本 'Hello, world!' 给访问者。
web.internalerror = web.debugerror
这一行告诉web.py,当发生错误时显示调试信息页。当站点正式启动后你应该把这行去掉以免用户看到它。
if __name__ == '__main__': web.run(urls, web.reloader)
这告诉web.py当本文件被执行时运行你的代码。第一个参数 urls
是前面定义的URL到函数的映射。另一个参数是一个“中间件”(middleware) —— 用来协助部分程序的封装函数(wrapper functions)。这里我们用的是reloader,当源代码发生变化时它会自动重新加载代码,这样我们就不用每次都重启服务了。站点正式启动后你可能会把想把它取消掉,但是当开发的时候这个功能是极为有用的。还有一个中间件 web.profiler
,它会输出每个函数运行所用的时间,这样你可以想办法让你的代码快一点儿。
执行 python code.py
来启动一个运行你的程序的web服务器,(要运行在8002端口,执行 python code.py 8002
)。你也可以让code.py以CGI脚本或FastCGI脚本的形式运行 —— 它会自动处理好。(由于 web.py
基于 WSGI,Python web程序接口标准,你可以用它在各种环境中,包括mod_python)
现在用浏览器访问你的站点,应该会看到 'Hello, world!'。
模板(Templates)
新建一个templates
目录,在该目录中打开一个新的.html文件,命名为 view.html
。
#if $name
I just wanted to say hello to $name.
#else
Hello, world!
#end if
现在回到 code.py
。编辑view.GET为以下内容:
name = 'Bob'
web.render('view.html')
现在用浏览器访问你的站点,应该会看到 'hello to Bob'。
这些模板是Cheetah 模板。所有的重要特性都可以在 一页纸教程中找到 —— 基本上,它们就像是嵌入HTML(或其他任何格式)的Python代码。
警告: 现在的计划是用一种简单一点但更强大的模板来取代Cheetah。这一模板格式已经设计好了,但是实现还没有完成。
自定义 URLs
编辑你的urls为:
'/(.*)', 'view'
现在改变view.GET的定义为:
def GET(self, name):
并删掉给name变量赋值的语句。
现在如果你访问 /Joe
应该能看到页面显示 'hello to Joe'。 如果你访问 /
,则应该显示'Hello, world!'。
数据库交互
在 web.run
那一行之上,加入:
web.db_parameters = dict(dbn='postgres', user='me', pw='pass', db='dbname')
根据你的数据库设置相应改变这些值(例如,MySQL用户可能要把dbn的值改为mysql
)。
在你的数据库中创建一个简单的表:
CREATE TABLE todo (
id serial primary key,
title text,
created timestamp default now(),
done boolean default 'f'
);
以及一个示例行:
INSERT INTO todo (title) VALUES ('Learn web.py');
回到 code.py
, 将这一行加到view.GET的顶部:
todos = web.select("todo")
编辑 view.html
为:
<ul>
#for todo in $todos
<li id="t$todo.id">$todo.title</li>
#end for
</ul>
现在访问你的网站应该能看到你的todo条目: 'Learn web.py'。
在 view.html
的尾部加入:
<form method="post" action="add">
<p><input type="text" name="title" /> <input type="submit" value="Add" /></p>
</form>
将 urls 列表改为:
'/', 'view',
'/add', 'add'
编辑 view.GET
去掉多余的参数:
def GET(self):
在 view
类后面加入:
class add:
def POST(self):
i = web.input()
n = web.insert('todo', title=i.title)
web.seeother('./#t'+str(n))
web.insert
返回新插入条目的id,然后 web.seeother
重定向用户到该条目。
速览: web.transact()
开始一次交易(transaction),web.commit()
提交它; web.rollback()
回溯。 web.update
类似 web.insert
但是它不是返回id而是接受id在表名之后做为参数(或一个WHERER子句字符串)。
现在你可以添加 todo 条目到列表中了。
另附: 存储对象
web.input
和 web.query
以及web.py中的其他一些东西会返回“存储对象”("Storage objects")。一个存储对象就像一个字典(dictionary),但是d.foo跟d['foo']是一样的。这省去了很多打字时间。
Cookies
Cookies 跟 web.input
的工作方式基本是一样的。 web.cookies()
返回一个包含所有已设置cookies的存储对象。 web.setcookie(name, value, expires="")
用来设置cookies。
web.input
和 web.cookies
接受一些参数和关键词参数。例如,如果你调用 web.input('color', times=1)
,而它没接收到叫color
的查询参数,它会抛出错误;如果没接收到 times
参数它会将其设为1。
一种常见做法是:
try: i = web.input('foo', bar=2)
except KeyError: return web.badrequest()