下面我们学习让用户从一个表单提交文本到程序中,并且把相关信息保存在session中。
web的工作原理
在建立表单前你需要了解一下web是怎么工作的,虽然不太完整,但是也能帮助你找出一些错误,而且创建表单也会更加容易。
我们从一个图开始,这个图展示了web请求不同部分和信息流向:
我加了一些线和字母来展示请求的过程:
- 你在浏览器输入网址http://learnpythonthehardway.org/,然后发送请求,请求通过A线到达你的电脑的网络接口。
- 请求再通过B线进入英特网,通过C线被服务器接收到。
- web程序通过D线取得请求,python代码运行index.GET.
- 但有return的时候,返回信息通过D线返回到服务器。
- 服务器再通过C线发送回应信息。
- 通过B线网络接口接收到信息,通过A线发送到浏览器。
- 最后,你的浏览器就可以展示回应的结果。
下面是一些常用的词汇表:
浏览器 - 这个不用解释了吧,IE,火狐这些东西就是了。
地址 - 通常指一个URL,就像http://learnpythonthehardway.org/这样的东西,http是你要使用的协议,就是“超文本传输协议”。你也可以试试ftp://ibiblio.ort,这是“文件传输协议”,后面的learnpythonthehardway.org就是域名,或者说是一个好记得地址,这个地址映射一个IP地址。最后,URL还有一个路径,比如http://learnpythonthehardway.org/book/中的/book/,它对应一个文件或者一些资源,还会有很多其他部分,不过这些是主要成分。
链接 - 一旦浏览器知道了你使用http协议,服务器、和资源,那么就要建立一个链接。浏览器会让操作系统打开一个端口,通常是80端口。当端口打开后,系统会回传一个类似文件的东西给你程序,这个文件的作用就是在你的电脑和服务器间发送和接收数据。使用http://localhost:8080的话,浏览器访问的是本机,使用的端口是8080替代了默认的80。你可以访问http://learnpythonthehardway.org:80/,和没加后面的端口是一样的,因为默认就是访问80端口。
请求 - 你的浏览器通过地址连接后,那么你需要从服务器请求你需要的东西。如果地址后有/book/,那么你想要取得book文件或者资源。通常服务器使用/book/index.html这个真实的文件,我们不关注具体是怎么做的,我们要知道我们发生一个请求给服务器,服务器返回python代码生成的东西。
服务器 - 服务器指的是浏览器另一端接收请求并返回文件或者资源的东西。大部分web服务器只是发生文件,只是主要的流量,但是你是用python组建一个服务器,它知道怎么接收请求,并且返回字符串。你可以假定是传输了文件,其实只是一些代码。
响应 - 这是服务器返回给浏览器的HTML代码。这些内容包含一些特定的头部信息,这样浏览器才知道获取的是什么类型的内容。以你的web程序为例,你发送时一样的东西,包括头部信息,只不过这些信息是python代码生成的。
上面这些可以帮助你更好的理解本节的内容,如果你还不是很理解上面的内容,去找一些资料了解了解。可以对照上面的图,把50章的代码对应到相应的部分,这样你就能大致明白它的工作原理了。
表单是怎么工作的
学习表单最好的办法就是写一个表单程序,修改你的app.py文件:
import web
urls = (
'/hello', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('templates/')
class Index(object):
def GET(self):
form = web.input(name="Nobody")
greeting = "Hello, %s" % form.name
return render.index(greeting = greeting)
if __name__ == "__main__":
app.run()
用CTRL+C停止程序,然后重新启动它,用浏览器访问http://localhost:8080/hello。你可以看到输出是“I just wanted to say Hello, Nobody.”改变地址为http://localhost:8080/hello?name=Frank,你会看到“Hello,Frank”。
让我们看看刚才做了什么:
- 使用web.input从浏览器取得数据,刚开始里面有一个默认值,当有?name=Frank的时候,Frank替换掉默认值。
- 用form.name替换greeting里面的值。
- 其他的和以前就一样了。
你也可以使用多个参数,比如地址改为http://localhost:8080/hello?name=Frank&greet=Hola,代码中改成这样:
greeting = "%s, %s" % (form.greet, form.name)
如果去掉&greet=Hola访问,你会得到一个错误,因为greet没有默认值。现在我们到程序中给他加一个空的默认值吧,并且判断一下他是否有值:
form = web.input(name="Nobody", greet=None)
if form.greet:
greeting = "%s, %s" % (form.greet, form.name)
return render.index(greeting = greeting)
else:
return "ERROR: greet is required"
创建HTML表单
在URL中输入参数比较麻烦,我们需要一个POST表单,这个HTML文件中包含<form>标签,标签中包含用户需要发送的信息。
创建一个包含表单的文件templates/hello_form.html:
<html>
<head>
<title>Sample Web Form</title>
</head>
<body>
<h1>Fill Out This Form</h1>
<form action="/hello" method="POST">
A Greeting: <input type="text" name="greet">
<br/>
Your Name: <input type="text" name="name">
<br/>
<input type="submit">
</form>
</body>
</html>
修改app.py文件:
import web
urls = (
'/hello', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('templates/')
class Index(object):
def GET(self):
return render.hello_form()
def POST(self):
form = web.input(name="Nobody", greet="Hello")
greeting = "%s, %s" % (form.greet, form.name)
return render.index(greeting = greeting)
if __name__ == "__main__":
app.run()
重启web程序,然后用浏览器访问一下。
现在你会看到一个表单,让你输入欢迎词和名字,当你点击提交按钮的时候,就会出现欢迎页面,而你的URL地址还是http://localhost:8080/hello。
在hello_form.html中的<form action="/hello" method="POST">告诉浏览器:
- 从form中收集用户输入。
- 通过POST方式发生数据给服务器。
- 发送的地址是/hello
你会看到<input>中的name和GET方式的相对应。
新的代码做了什么:
- 先以GET的方式访问/hello,代码里面是访问了hello_form.html文件。
- 在浏览器中添加了一个form,这个表单设定了发生数据的方式给POST。
- web程序运行POST部分的代码处理发送过来的数据。
- POST像以前一样发送数据到hello页面。
在index.html页面中添加一个返回的连接,让你可以返回到表单页面。
创建一个布局模板
下一个练习中,我们要把游戏放进来,这样会有很多HTML页面要写,这样很麻烦,幸运的是,我们可以创建一个布局模板,可以让其他页面包含相同的头部和尾部文件。一个好的程序员要减少重复。
改变index.html文件成这样:
$def with (greeting)
$if greeting:
I just wanted to say <em style="color: green; font-size: 2em;">$greeting</em>.
$else:
<em>Hello</em>, world!
把hello_form.html改成下面这样:
<h1>Fill Out This Form</h1>
<form action="/hello" method="POST">
A Greeting: <input type="text" name="greet">
<br/>
Your Name: <input type="text" name="name">
<br/>
<input type="submit">
</form>
我们做的就是去掉了所有页面都一样的头部和尾部。然后再添加这么一个页面templates/layout.html:
$def with (content)
<html>
<head>
<title>Gothons From Planet Percal #25</title>
</head>
<body>
$:content
</body>
</html>
这个文件看起来像模板。它从其他页面取得content,然后包含进来。注意$:content的用法,和其他模板变量不太一样。
最后我们改一下web程序:
render = web.template.render('templates/', base="layout")
这就告诉了lpthw.web使用layout.html作为基础模板文件。重启程序看看效果吧。
为表单写自动化测试用例
测试web程序只要刷新浏览器就可以了,不过我们是程序员嘛,为什么不写一个简单的测试代码呢。
在bin中创建一个__init__.py文件。这样python就会认为bin是一个目录了。
创建tests/tools.py文件,加入下面的代码:
from nose.tools import *
import re
def assert_response(resp, contains=None, matches=None, headers=None, status="200"):
assert status in resp.status, "Expected response %r not in %r" % (status, resp.status)
if status == "200":
assert resp.data, "Response data is empty."
if contains:
assert contains in resp.data, "Response does not contain %r" % contains
if matches:
reg = re.compile(matches)
assert reg.matches(resp.data), "Response does not match %r" % matches
if headers:
assert_equal(resp.headers, headers)
然后可以编写你的自动化测试代码了,建立文件tests/app_tests.py:
from nose.tools import *
from bin.app import app
from tests.tools import assert_response
def test_index():
# check that we get a 404 on the / URL
resp = app.request("/")
assert_response(resp, status="404")
# test our first GET request to /hello
resp = app.request("/hello")
assert_response(resp)
# make sure default values work for the form
resp = app.request("/hello", method="POST")
assert_response(resp, contains="Nobody")
# test that we get expected values
data = {'name': 'Zed', 'greet': 'Hola'}
resp = app.request("/hello", method="POST", data=data)
assert_response(resp, contains="Zed")
最后使用nosetests测试程序:
root@he-desktop:~/python/projects/gothonweb# nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.192s
OK
我就是把app.py模块都导入进来,然后手动运行这个程序,lpthw.web有个API用来处理请求:
app.request(localpart='/', method='GET', data=None, host='0.0.0.0:8080',
headers=None, https=False)
你可以把URL作为第一个参数,修改里面的东西,这样就不用启动web服务器,你就可以自动测试了。
你要用tests.tools中的assert_response函数来验证响应:
assert_response(resp, contains=None, matches=None, headers=None, status="200")
这个函数包括挺多东西,自己研究一下吧。
在app_tests.py中,我们先确定/返回一个404错误。因为这个地址是不存在的。然后检查了/hello在GET和POST的请求能正常工作。这些代码很好懂的。
加分练习
- 了解更多HTML的知识,设计一个更好的布局。
- 研究一下怎么上传文件,试着上传一个图片然后保存到目录中。
- 找到HTTP RFC文件阅读一下。
- 找人帮你设置一个服务器,比如Apache, Nginx, 或者thttpd。
- 多创建一些web程序。你应该仔细阅读web.py中关于会话的内容。这样你能够明白怎么保存用户状态信息。
分享到:
相关推荐
learn-python-the-hard-way中文版,o基础学习python!||随手上传是种美德
Shaw is the author of the popular online books Learn Python the Hard Way, Learn Ruby the Hard Way, and Learn C the Hard Way. He is also the creator of several open source software projects like ...
Learn-Python-3-the-Hard-Way.pdf
Learn Python The Hard Way, 2nd Edition 英文版 属于独家制作 原创 PDF格式的之前一直上传不了,现在终于可以了http://download.csdn.net/source/3501806, 也可以去我的网盘下载 DBank:...
Learn Python the Hard Way
learn python the hard way 实例代码
Learn Python the Hard Way, 3rd Edition
learn python the hard way.
Learn Python the Hard Way 中文三版 Learn Python the Hard Way 中文三版
In Learn Python 3 the Hard Way, Zed Shaw taught you the basics of Programming with Python 3. Now, in Learn More Python 3 the Hard Way, you’ll go far beyond the basics by working through 52 ...
Learn Python The Hard Way(3rd) 英文无水印pdf 第3版 pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请...
Learn Python the Hard Way(包括中文和英文),不错的python教程
You Will Learn Python!
这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。 本书结构非常简单,共包括52个习题,其中26个覆盖了输入/输出...
Learn Python 3 The Hard Way . pdf epub azw3 https://learnpythonthehardway.org/python3/ 原始文件是azw3版本,pdf和epub版本是从azw3版本转换生成。 Learn Python 3 the Hard Way now uses Python 3.6. I’ve ...
learn python 3 the hard way provides an easy step towards complicated programming in python 3.
Learn Python The Hard Way(笨办法学python) 原书代码
Learn Python The Hard Way - 2011.pdf