七天学会Python编程 -- 第九章 Web开发

9.1 Web 基础

大家都知道上网,不管是通过电脑,还是手机或平板电脑,这里讲讲 Web 的一些基础内容。

首先我们用来上网的设备都会有个软件叫浏览器,浏览器的形式可能是多种多样的,例如常见的 IE 浏览器和 Chrome 谷歌浏览器,属于标准的浏览器软件,还有像在微信中打开一些页面的形式,是属于微信中内嵌的浏览器,还有些 APP 解析一些网页内容后只显示网页的部分内容,这也属于浏览器的一种形式。

然后浏览器访问的服务器叫作 Web 服务器,Web 服务器返回给浏览器网页内容,浏览器解析后显示出来。网页是用一种叫作 HTML 的标记型语言写的,一个简单的网页可以是这样的:

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<h1>这是标题</h1>
</head>

<body>
这里是内容
</body>

</html>

整个过程是这样:浏览器访问一个网址,网址对应到一个 Web 服务器,Web 服务器会把网页内容返回给浏览器,浏览器解析网页内容后显示出来。

网页内容可以是保存在一个扩展名为 .html 的文件,例如 test.html,也可以是一个 Python 程序生成的,我们这一章会讲怎样通过 Python 程序开发网页功能。

9.2 安装一个比较热门的 Web 开发框架

我们会用 Flask,Flask 是一个比较流行的 Python Web 开发框架,优点是简单易懂,可以很快上手,开发网页程序。

这里先要安装这个框架,这个框架可以看作是比较复杂的模块,我们要学习怎么安装它。

如果你使用了树莓派或其他 Linux 环境,安装 Flask 很简单,只需要这个命令

pip install Flask

这个命令会把 Flask 和 Flask 所用到的其他模块都一起安装好。

在 Windows 下安装复杂一些,一般是先安装上 pip 这个 Python 包管理工具,然后也是通过 pip install Flask 命令来安装。

可以参考这篇教程上安装 pip 工具的方法安装好 pip,然后也是通过 pip install Flask 安装 Flask 框架。

windows下面安装Python和pip终极教程

http://www.cnblogs.com/yuanzm/p/4089856.html

这里概要总结一下安装过程,先安装 Python,记得把 Python 的安装目录和下面的 Scripts 目录加到系统路径中,如果你的 Python 安装在 C:\Python27 目录下,就把 C:\Python27 和 C:\Python27\Scripts 这两个目录加到系统路径下。

然后从这个网址下载 pip 安装包

https://pypi.python.org/pypi/pip#downloads

记得下载扩展名为 .tar.gz 的,下载下来后是个压缩包格式,可以用 WinRAR 或其他解压缩工具解压缩到一个目录下,然后从命令行里 cd 这个解压缩后的目录下,执行命令 python setup.py install,就可以安装好 pip 工具。

安装好后在命令行里运行 pip install Flask 就可以顺利安装 Flask 框架。

9.3 做一个简单的页面

现在我们开始学习用 Flask 做一个简单的页面,是在页面上打印 “Hello World!”。

先建一个保存这次程序的目录,保存下面代码为 hello.py:

1
2
3
4
5
6
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

逐行解释一下,第一行是指引入 Flask 模块,这个指令跟我们以前章节学过的不太一样,它是从 flask 这个模块包里引入 Flask 模块,模块包的概念我们在模块章节有讲过,是为了进一步对模块做分类,特别是对于一些复杂的模块,有必要再分模块包。

第二行是定义一个 Flask 对象类型,并赋给 app 变量,name 是 Python 内置的一个变量,主要 name 前后分别是两个下划线,这个内置变量的值是当前运行的程序名字,对于主程序来说这个值是 main,如果在一个模块中这个值会是模块的名字。app = Flask(name) 是定义一个对象,name 作为初始参数,对象类型是 Flask,把定义的对象赋给变量 app。

第三行 @app.route(“/“) 是 Flask 框架的一种使用方式,表示定义一个网址路径,“/” 表示是根目录,就像我们访问百度这个网址 http://www.baidu.com/ 时,对应的就是 “/” 这样一个根目录网址路径。

第四行和第五行是定义一个函数,返回一个字符串。

在 Linux 环境下,在命令行里执行这个命令

FLASK_APP=hello.py flask run

如果在 Windows 环境下,要在命令行状态下,执行两条命令,先执行第一条,再执行第二条:

set FLASK_APP=hello.py

flask run

命令行里提示这样的信息

后表示 Web 服务已经成功运行起来了,同时按 CTRL 键和 C 键会退出服务。

你现在可以用浏览器访问网址 http://127.0.0.1:5000/ 就可以看到打印出来的 “Hello World!”。

解释一个这个命令,FLASK_APP=hello.py 是定义一个环境变量,然后执行 flask run 命令,flask run 命令里会用到 FLASK_APP 环境变量里定义的那个文件名字,就会运行起来。

下面继续完善一下,输出一个真正的网页,我们把前面章节那段 HTML 输出,上面代码这样修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
return '''<html>
<head>
<h1>This is a head</h1>
</head>
<body>
This is the content.
</body>
</html>'''

留意一下那个 hello 函数中的 return 指令,是返回一个字符串,因为这个字符串是跨多行的,所以用了 Python 的一种特殊用法,可以前后用三个单引号或三个双引号把多行字符串括起来,我们也用缩进的方式提高可读性。

按 CTRL + C 退出服务后再启动,再访问一下网址 http://127.0.0.1:5000/ 试试,能看到一个真正网页的显示内容,有标题有内容。

9.4 做一个比较复杂的网页功能

这一节我们尝试做一个比较复杂的网页功能,是管理联系人信息,我们维护一个类似下面的数据表格:

Name Mobile

John 1300000

Tom 1350000

Mary 1380000

首先讲一下怎样保存这样的表格数据,我们可以使用列表,过去我们学过的列表是保存多个数值,其实列表可以保存绝大多数对象,也可以保存列表对象。比如这样的列表:

1
a = [10, 20, 30]

是保存了3个数字,而这样的列表:

1
b = [ ["John", "1300000"], ["Tom", "1350000"], ["Mary", "1380000"] ]

是保存了3个列表对象,我们可以用 b[0] 获取第一个列表对象,b[1] 获取第二个列表对象,依次类推。

我们就是利用这种列表来保存这次的联系人数据,然后再用我们保存对象到文件的方法把这个大列表保存到硬盘一个文件里,这样可以以后再加载出来。

联系人清单功能

我们首先做个网页,是显示已有的联系人清单,然后做个新增的功能,可以增加新联系人,然后再做一个删除联系人的功能,这样基本的联系人管理功能就具备了。

参考前面章节的简单页面的例子,先写一下显示联系人清单的页面功能,这一次我们保存程序文件为 contacts.py。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import pickle
from flask import Flask

app = Flask(__name__)

def load_data_from_file(filePath):
file = open(filePath, "rb")
dataObject = pickle.load(file)
return dataObject

def save_data_to_file(filePath, dataObject):
file = open(filePath, "wb")
pickle.dump(dataObject, file)

@app.route("/init")
def init():
b = [ ["John", "1300000"], ["Tom", "1350000"], ["Mary", "1380000"] ]
save_data_to_file("contacts.dat", b)
return "Init successfully."

@app.route("/list")
def list():
webContent = '''<html>
<head>
<h1>Contacts Management</h1>
</head>
<body>'''

webContent = webContent + "<table><tr><td>Name</td><td>Mobile</td></tr>"

dataList = load_data_from_file("contacts.dat")

for contact in dataList:
webContent = webContent + "<tr><td>" + contact[0] + "</td><td>" + contact[1] + "</td></tr>"

webContent = webContent + "</table>"

webContent = webContent + "</body></html>"

return webContent

启动 Flask 后先访问网址 http://127.0.0.1:5000/init 初始化一些数据,然后再访问网址 http://127.0.0.1:5000/list 可以看到显示的联系人清单。

这段代码涉及内容比较多,先自己读一下看能否理解。

程序的主体部分跟前面章节的简单页面例子差不多,只是多了两个对应不同网址的函数,一个是 /init 对应方法 init,这个方法是先初始化一点数据,另一个是 /list 对应方法 list,用于显示已有的联系人信息。

还有两个函数一个是用于保存数据的 save_data_to_file,另一个是加载数据的 load_data_from_file,留意一下函数所用的参数。

在 list 函数里有 webContent 这个变量,是用于保存网页内容,这次我们的网页内容是通过程序动态生成的,

1
webContent = webContent + "html codes"

这种用法是在 webContent 后面追加 “html codes” 这个字符串,例如一开始 webContent 内容是 “web content “,执行了上面代码后 webContent 内容变为 “web content html codes”。在 list 函数里用了很多这种方式来组装网页内容,最后再返回给用户的浏览器端显示出来。

网页代码方面,里面用了几种 HTML 标签语法,主要是 table,table 是用于定义一个表格,里面通过 tr 标签定义行,然后通过 td 标签定义列,具体用法可以自己上网搜索一下。

list 方法的主要目的是组装网页代码,其中表格里面的内容是根据联系人数据生成的,以后在联系人数据变化时网页显示内容也会跟着变化。

增加联系人功能

下面再加上增加联系人功能,我们在联系人表格下面增加一个输入表单,用到 form 相关的 HTML 标签语法,主要是输入框和提交按钮等。这里只显示 list 方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@app.route("/list")
def list():
webContent = '''<html>
<head>
<h1>Contacts Management</h1>
</head>
<body>'''

webContent = webContent + "<table><tr><td>Name</td><td>Mobile</td></tr>"

dataList = load_data_from_file("contacts.dat")

for contact in dataList:
webContent = webContent + "<tr><td>" + contact[0] + "</td><td>" + contact[1] + "</td></tr>"

webContent = webContent + "</table>"

webContent = webContent + "<form action='/save_contact' method='post'>Name: <input type='text' name='name'/> Mobile: <input type='text' name='mobile'/> <input type='submit'/></form>"

webContent = webContent + "</body></html>"

return webContent

我们可以看到,是增加了一行代码,这行代码是增加联系人表单的 HTML 网页代码,可以上网搜索 “html form” 这样的关键词去搜索一下相关内容。

在 form 网页里有个

1
<form action='/save_contact' method='post'>

这里的 action 意思是用户点击 “提交” 按钮是传给哪个函数,这个函数会负责把用户录入的数据保存起来,method=’post’ 表示表单提交的方式,”post” 是表单比较常用的提交方式。

我们需要在程序里加一个 save_contact 函数,下面只显示这个函数的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from flask import request

@app.route("/save_contact", methods=['GET', 'POST'])
def save_contact():
name = request.form.get("name")
mobile = request.form.get("mobile")

dataList = load_data_from_file("contacts.dat")
dataList.append( [name, mobile] )
save_data_to_file("contacts.dat", dataList)

return '''<html>
<head><h3>Add successfully!</h3></head>
<body>
<a href="/list">Click to return</a>
<body>
</html>
'''

解释一下这段代码,@app.route(“/save_contact”, methods=[‘GET’, ‘POST’]) 这行里除了定义网址信息以外,还定义了允许的调用方式,”GET” 和 “POST” 是 Web 应用领域的概念,是指数据提交方式,现在可以不用太深究,只记住比较常用的是 “POST” 方式就可以。

按 CTRL + C 停止 Web 服务后再用命令 FLASK_APP=contacts.py flask run 启动服务,访问网址 http://127.0.0.1:5000/list 可以查看已有的联系人清单,在清单下面有两个输入框,一个是输入名字的,另一个是输入手机号码的,还有个 “提交” 按钮,输入你要增加的联系人的名字和手机号码后点 “提交” 按钮就可以保存数据,会转到一个提示保存成功的页面,点击上面的返回连接可以返回到联系人清单显示页面。

删除联系人功能

删除联系人是在联系人清单表格的每行后面增加一个删除链接,用户点击时会调用我们一个函数,这个函数拿到要删除的联系人信息后进行删除操作,然后提示操作成功,用户可以返回到清单显示界面。

这里我们要学习一个列表的操作方法,是删除某个数据的方法,看下面代码:

1
2
3
4
5
a = [10, 20, 30]

del(a[1])

print(a)

这段代码运行打印输出的列表数据只有2个,10 和 30,第二个数字 20 被删掉了,这就是对列表数据的删除操作。类似道理,如果想删除联系人清单中某一条数据,可以通过列表索引值的方式删除。

比如这个列表:

1
b = [ ["John", "1300000"], ["Tom", "1350000"], ["Mary", "1380000"] ]

用 del(b[1]) 的方式就可以删掉上面列表中的第二个子列表对象,也就是删除第二行数据。

下面开始我们的删除联系人代码,先在清单列表显示中增加删除链接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@app.route("/list")
def list():
webContent = '''<html>
<head>
<h1>Contacts Management</h1>
</head>
<body>'''

webContent = webContent + "<table><tr><td>Name</td><td>Mobile</td><td> </td></tr>"

dataList = load_data_from_file("contacts.dat")

index = 0
for contact in dataList:
webContent = webContent + "<tr><td>" + contact[0] + "</td><td>" + contact[1] + \
"</td><td><a href='/delete_contact?index=" + index + "'>Delete</a></td></tr>"
index = index + 1

webContent = webContent + "</table>"

webContent = webContent + "<form action='/save_contact' method='post'>Name: <input type='text' name='name'/> Mobile: <input type='text' name='mobile'/> <input type='submit'/></form>"

webContent = webContent + "</body></html>"

return webContent

上面代码中,我们是在 table 标签里增加了一个列,这个列为每行数据放一个删除链接,在连接里我们用到一个 index 变量,是记录循环遍历列表时的索引值,并作为参数通过 /delete_contact?index=某数值 的方式传递给 /delete_contact 这个网址,这个网址对应一个函数,是我们要增加的,这个函数会根据列表索引值删除对应的记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@app.route("/delete_contact", methods=['GET'])
def delete_contact():
index = request.args.get('index')

dataList = load_data_from_file("contacts.dat")
del( dataList[int(index)] )
save_data_to_file("contacts.dat", dataList)

return '''<html>
<head><h3>Delete successfully!</h3></head>
<body>
<a href="/list">Click to return</a>
<body>
</html>
'''

解释一下这段代码,@app.route(“/delete_contact”, methods=[‘GET’]) 这行定义了网址,也定义了允许的调用方式为 GET,也就是通过网址传递参数的方式,例如像 /delete_contact?index=某数值 这样。

代码里关键是先拿到网址里传得参数 index,是这一行 index = request.args.get(‘index’),这是 Flask 框架提供的方法,然后从文件中加载数据,然后用 del( dataList[int(index)] ) 删除对应索引值的列表对象,里面有个 int(index) 用法,这里 index 变量是字符串类型,从网址里传的值默认是字符串类型,要先转成数字类型才能在这里用。

删除成功后保存最新列表到数据文件中,然后显示删除成功的信息,用户可以点击返回到清单显示页面。

到现在为止,我们已经完成了这次复杂的网页功能开发,具备比较完整的数据管理功能,可以用来管理联系人信息。

恭喜你学到了这么多内容!

9.5 实践练习时间

过去章节我们学习了 Web 开发相关内容,下面通过实践练习来加深理解。

练习1:

仿照那个联系人管理功能开发一个考试成绩管理网页功能,数据列有 姓名、语文、数学、英语,能够显示清单,能够增加和删除。

注意:如果程序里有中文字符,需要在程序第一行放这行代码

1
# -*- coding: utf-8 -*-

以防止报错,这样代码是让 Python 程序支持中文字符。

练习2:

在练习1中我们是用列表中再用列表来表示每行数据的方式,在这个基础上调整一下程序,改成列表中用字典的方式实现这个程序,也就是说数据存储是这样的:

[ {“name”: “John”, “mobile”: “1300000”}, {“name”: “Tom”, “mobile”: “1350000”}, {“name”: “Mary”, “mobile”: “1380000”} ]

保存到文件和从文件加载数据时是对整个列表,而列表内部的每行数据是按字典格式存储。