本网页是 http://webpy.infogami.com/tutorial2.en 的翻译版本,用Firefox获取最佳浏览效果

web.py 0.2 tutorialweb.py 0.2 教程


So you know Python and want to make a website. web.py provides the code to make that easy.既然你已经了解了 Python 并且想做一个网站。web.py 提供了代码使这个过程变得简单。

If you want to do the whole tutorial, you'll need to have installed Python, web.py, flup, psycopg2, and Postgres (or equivalent database and Python driver). For details, see the webpy.org.如果你想做完整个教程,你需要安装 Python,web.py,psycopg2 和 Postgres(或者其他的数据库以及相应的 Python 驱动)。从 webpy.org 获取细节。

If you have an existing web.py project, take a look at the upgrade page for info on migrating.如果你已经有了一个应用 web.py 的项目,从这个 upgrade 页面中你可以获得 migration 的信息。

Let's get started.让我们开始吧。

URL HandlingURL 处理

The most important part of any website is its URL structure. Your URLs aren't just the thing that your visitors see and email to their friends, they also provide a mental model of how your website works. On popular sites like del.icio.us, the URLs are even part of the user interface. web.py makes it easy to make great URLs.任何一个网站最重要的部分都是它的 URL 结构,URLs 不仅仅用来让网站的访问者看到或者 email 告诉他们的朋友,它还告诉别人你的网站是按照怎样的思维模式工作的。像 del.icio.us 这样的网站,它的 URLs 甚至是用户界面的一部分。web.py 让使用很棒的 URLs 变得很容易。

To get started with your web.py application, open up a new text file (let's call it code.py) and type:下面开始写基于 web.py 的应用程序,新建一个文本文件(让我们给它起名 code.py )并且输入:

import web

This imports the web.py module.这句话的作用是引入 web.py 模块。

Now we need to tell web.py our URL structure. Let's start out with something simple:现在需要告诉 web.py 我们的 URL 结构。刚开始我们写个简单的:

urls = (
  '/', 'index'

The first part is a regular expressions that matches a URL, like /, /help/faq, /item/(\d+), etc. (The \d+ matches a sequence of digits. The parentheses say to capture that piece of the match for later on.) The second part is the name of a class to send the request to, like index, view, welcomes.hello (which gets the hello class of the welcomes module), or get_\1. \1 is replaced by the first capture of your regular expression; any remaining captures get passed to your function.第一部分是一个正则表达式,它用来匹配一个 URL,例如 //help/faq/item/(\d+) 等等。(\d+ 匹配的是一串数字。括号表示匹配上部分供以后使用),第二部分是处理请求的类的名字,例如 indexviewwelcome.hellowelcomes 模块的 hello 类),或者 get_\1\1 用来被正则表达式捕捉到的第一部分替换,捕捉到的剩下的部分被传递给方法。

This line says we want the URL / (i.e. the front page) to be handled by the class named index.这一行的意思是我们把 URL 是 /(例如说首页)的请求传给 index 类来处理。

Now we need to write the index class. While most people don't notice it just browsing around, your browser uses a language known as HTTP for communicating with the World Wide Web. The details aren't important, but the basic idea is that Web visitors ask web servers to perform certain functions (like GET or POST) on URLs (like / or /foo?f=1).现在我们需要写 index 类。大部分人上网只是随便看看,他们不会注意到浏览器用的是一种被称为 HTTP 的语言与 World Wide Web 进行交流。这其中的细节不重要,但是有一个基本的概念,网站访问者让服务器根据 URLs(例如 / 或者 /foo?f=1)处理相应的动作(例如 GETPOST)。

GET is the one we're all familiar with, the one used to request the text of a web page. When you type harvard.edu into your web browser, it literally asks the Harvard web server to GET /. The second-most famous, POST, is often used when submitting certain kids of forms, like a request to purchase something. You use POST whenever the act of submitting a request does something (like charge your credit card and process an order). This is key, because GET URLs can be passed around and indexed by search engines, which you definitely want for most of your pages but definitely don't want for things like processing orders (imagine if Google tried to buy everything on your site!).GET 动作我们很熟悉,它被用来请求一个文本形式的网页。当你在浏览器地址栏输入 harvard.edu 后,它会 GET 哈佛大学网站服务器的 /POST 动作我们也不陌生,它经常被用来提交相应的表单,例如一个购买东东的请求。只要你在网上做一个提交请求的动作(比方说用信用卡下一个定单),你就会用到 POST。了解这两个动作的不同之处很关键,因为 GET 方式的 URLs 可以被传送和被搜索引擎索引,你一定希望你网站上大部分的网页被索引,但是你也一定不希望正在处理的定单被索引(想象一下如果 Google 试图购买你网站上所有的东东!)。

In our web.py code, we make the distinction between the two clear:在 web.py 代码里,我们把这两个动作区别得很清楚:

class index:
    def GET(self):
        print "Hello, world!"

This GET function will now get called by web.py anytime some makes a GET request for /.只要有人提给服务器一个 URL 为 /GET 请求,上面的 GET 方法将被 web.py 调用。

Alright, now we just need to finish up with a final line telling web.py to start serving web pages:好了,现在我们需要完成程序的最后一行,告诉 web.py 开始提供网页服务:

if __name__ == "__main__": web.run(urls, globals())

This tells web.py to serve the URLs we listed above, looking up the classes in the global namespace of this file.这句话是让 web.py 在这个文件(code.py)的全局名称空间里查找相应的类给上面列出的 URLs 提供相应的服务。

Now notice that although I've been talking a lot here, we only really have five or so lines of code. That's all you need to make a complete web.py application. If you go to your command line and type:现在请注意,尽管我在这儿叽叽歪歪讲了一大堆,可是我们实际上就写了 5 行代码。这就是我们写一个完整的 web.py 应用程序所需要的全部。如果你去命令行窗口输入:

$ python code.py
Launching server:

You now have your web.py application running a real web server on your computer. Visit that URL and you should see "Hello, world!" (You can add an IP address/port after the "code.py" bit to control where web.py launches the server. You can also tell it to run a fastcgi or scgi server.)现在你的 web.py 应用程序就运行在一个真实的 web server 中了。访问那个 URL(http://localhost:8080),你应该看到“Hello, world!”(你可以在命令行的 code.py 后面添加 IP 地址/端口来控制 web.py 启动 server 的位置。你也可以使用 fastcgi 或者 scgi 参数来运行相应类型的服务。)


web.py also has a few tools to help us with debugging. Before the last line, add:web.py 也有一些工具帮助我们 debug。在最后一行前面加上:

web.webapi.internalerror = web.debugerror

This will give you more helpful error messages. And on the last line add web.reloader so that it reads:这将提供给你许多有帮助的出错信息。然后在最后一行加上 web.reloader

if __name__ == "__main__": web.run(urls, globals(), web.reloader)

This tells web.py to use the web.reloader "middleware" (middleware is a wrapper function to add some functionality to your web server) which reloads your files whenever you edit them, so that you can see the changes in your web browser right away. (For some serious changes, though, you'll still have to restart the server.) You'll probably want to take this out when you make your site public, but it's great while developing. There's also web.profiler, which outputs information about how much time each function took at the end of each web page, so that you can make your code faster.这是告诉 web.py 使用 web.reloader“中间件”(中间件是一个包装好的方法,用来在你的 web server 里添加一些功能),web.reloader 的作用是随时重新加载你编辑过的文件,以便你在浏览器里看到变化。(然而对于一些重要的改变,你还是要重启 server。)如果你的网站已经发布了,你也许不想要这样的功能,但是在网站的开发阶段,这个功能很有用。还有一个 web.profiler 的中间件,它可以在每个网页的底部输出每个方法运行消耗的时间,这样可以帮助你让代码运行得更快。


Writing HTML from inside Python can get cumbersome; it's much more fun to write Python from inside HTML. Luckily, web.py makes that pretty easy.在 Python 里面写 HTML 是非常让人厌倦的;而在 HTML 里面写 Python 则要有意思的多。幸运的是,web.py 让这一切变得很简单。

Let's make a new directory for our templates (we'll call it templates). Inside, make a new file whose name ends with HTML (we'll call it index.html). Now, inside, you can just write normal HTML:让我们为模版新建一个目录(目录名是templates)。我们再在这个目录里新建一个扩展名是 html 的文件(我们叫它 index.html)。现在,你可以在这个文件里写普通的 HTML:

<em>Hello</em>, world!

Or you can use web.py's templating language to add code to your HTML:或者你可以用 web.py 的模版语言往 html 文件里添加代码:

$def with (name)

$if name:
    I just wanted to say <em>hello</em> to $name.
    <em>Hello</em>, world!

Note: Currently, four spaces are required for indentation.注意:现在代码里需要有 4 个空格的缩进。

As you can see, the templates look a lot like Python files except for the def with statement at the top (saying what the template gets called with) and the $s placed in front of any code. Currently, template.py requires the $def statement to be the first line of the file. Also, note that web.py automatically escapes any variables used here, so that if for some reason name is set to a value containing some HTML, it will get properly escaped and appear as plain text. If you want to turn this off, write $:name instead of $name.正如你看到的,除了顶部有 def with 的声明(saying what the template gets called with)以及每行代码开头都有 $ 外,这个模版有点像 Python 文件。目前,template.py 要求 $def 声明在文件的第一行。而且请注意,web.py 会自动转义在这儿使用的任何变量,这样,如果为了某种需要,name 被赋成一个包含 HTML 的值,它将得到正确地转义并作为平文本显示出来。如果你想关掉这个功能,用 $:name 代替 $name

Now go back to code.py. Under the first line, add:现在回到 code.py,在第一行下面加上:

render = web.template.render('templates/')

This tells web.py to look for templates in your templates directory. Then change index.GET to: 这名话的意思是告诉 web.py 在 templates 目录中寻找模版文件。然后把 index.GET 改成:

name = 'Bob'
print render.index(name)

Visit your site and it should say hello to Bob.访问你的站点,它应该变为 say hello to Bob 了。

Development tip: Add , cache=False to the end of your render call to have web.py reload your templates every time you visit the page.小技巧:把 cache=False 加在 render 的语句后面,这样你每次访问页面时 web.py 都会重新加载模版文件。

Now change your URL line to:现在改变 URL 那一行语句为:

'/(.*)', 'index'

and change the definition of index.GET to:接着改 index.GET 的定义为:

def GET(self, name):

and delete the line setting name. Visit / and it should say hello to the world. Visit /Joe and it should say hello to Joe.然后删除给 name 赋值的语句。访问 / ,页面应该是 say hello to the world。访问 /Joe ,页面应该是 say hello to Joe。


Above your web.run line add:web.run 这一句之上添加:

web.config.db_parameters = dict(dbn='postgres', user='username', pw='password', db='dbname')

(Adjust these -- especially username, password, and dbname -- for your setup. MySQL users will also want to change dbn to mysql.)(按照你自已的设置调整这些参数——特别是 usernamepassworddbname,MySQL 的用户需要把 dbn 的值改成 mysql。)

Create a simple table in your database:在你的数据库里创建一个简单的表:

  id serial primary key,
  title text,
  created timestamp default now(),
  done boolean default 'f'

And an initial row:并且添加一条初始的条目:

INSERT INTO todo (title) VALUES ('Learn web.py');

Back in code.py, change index.GET to:回到 code.py ,改变 index.GET 为:

def GET(self):
    todos = web.select('todo')
    print render.index(todos)

and change back the URL handler to take just /.再把处理 URL 的语句改回成 /

Edit index.html so that it reads:按下面代码编辑 index.html

$def with (todos)
$for todo in todos:
    <li id="t$todo.id">$todo.title</li>

Visit your site again and you should see your one todo item: "Learn web.py". Congratulations! You've made a full application that reads from the database. Now let's let it write to the database as well.访问你的站点,你应该可以看到一条 todo 项目:“Learn web.py”。恭喜!你已经有一个读数据库的完整的应用程序了。

At the end of index.html, add:index.html 文件末尾添加:

<form method="post" action="add">
<p><input type="text" name="title" /> <input type="submit" value="Add" /></p>

And change your URLs list to read:然后改你的 URLs 列表为:

'/', 'index',
'/add', 'add'

(You've got to be very careful about those commas. If you omit them, Python adds the strings together and sees '/index/addadd' instead of your list of URLs!)(对逗号的使用你要非常小心。如果你忽略它们,Python 将把这些字符串合在一起,你的 URLs 列表将变成'/index/addadd'!)

Now add another class:现在再写一个类:

class add:
    def POST(self):
        i = web.input()
        n = web.insert('todo', title=i.title)

(Notice how we're using POST for this?)(注意在这里我们是怎样应用 POST 的?)

web.input gives you access to any variables the user submitted through a form. web.insert inserts values into the database table todo and gives you back the ID of the new row. seeother redirects users to that ID.web.input 让你得到用户通过提交表单传递给你的所有变量。web.insert 把值插入到数据库中的 todo 表中并且返回新条目的 ID 。seeother 重定向用户到这个 ID。

Quickly: web.transact() starts a transaction. web.commit() commits it; web.rollback() rolls it back. web.update works just like web.insert except instead of returning the ID it takes it (or a string WHERE clause) after the table name.速览:web.transact() 开启一个事务(transaction)。web.commit() 提交这个事务;web.rollback() 回滚这个事务。web.updateweb.insert 差不多,但是它不是返回 ID 而是 it takes it(或者一个 WHERE 子句)after the table name.

web.input, web.query, and other functions in web.py return "Storage objects", which are just like dictionaries except you can do d.foo in addition to d['foo']. This really cleans up some code.web.inputweb.queryweb.py 中的其它一些方法可以返回“存储对象(Storage objects)”,它就像字典(dictionaries),你可以写 d.foo 也可以写 d['foo']。这确实使代码变得干净整洁。

You can find the full details on these and all the web.py functions in the documentation.你可以在这篇文档里找到关于这些的全部细节和 web.py 的所有方法。

This ends the tutorial for now. Take a look at the documentation for lots more cool stuff you can do with web.py.现在教程结束了。阅读这篇文档吧,你可以用 web.py 做更多更酷的事情。