Skip to content

Commit e30ef31

Browse files
committed
add flask web.
1 parent 5552d59 commit e30ef31

99 files changed

Lines changed: 9594 additions & 4137 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

04_flask/01_Flask介绍.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# 第 1 章:Hello, Flask!
2+
3+
追溯到最初,Flask 诞生于 Armin Ronacher 在 2010 年愚人节开的一个玩笑。后来,它逐渐发展成为一个成熟的 Python Web 框架,越来越受到开发者的喜爱。目前它在 GitHub 上是 Star 数量最多的 Python Web 框架,没有之一。
4+
5+
Flask 是典型的微框架,作为 Web 框架来说,它仅保留了核心功能:**请求响应处理****模板渲染**。这两类功能分别由 Werkzeug(WSGI 工具库)完成和 Jinja(模板渲染库)完成,因为 Flask 包装了这两个依赖,我们暂时不用深入了解它们。
6+
7+
## 主页
8+
9+
这一章的主要任务就是为我们的程序编写一个简单的主页。主页的 URL 一般就是根地址,即 `/`。当用户访问根地址的时候,我们需要返回一行欢迎文字。这个任务只需要下面几行代码就可以完成:
10+
11+
*app.py:程序主页*
12+
13+
```python
14+
from flask import Flask
15+
app = Flask(__name__)
16+
17+
@app.route('/')
18+
def hello():
19+
return 'Welcome to My Watchlist!'
20+
```
21+
22+
按照惯例,我们把程序保存为 app.py,确保当前目录是项目的根目录,并且激活了虚拟环境,然后在命令行窗口执行 `flask run` 命令启动程序(按下 Control + C 可以退出):
23+
24+
```bash
25+
(env) $ flask run
26+
* Serving Flask app "app.py"
27+
* Environment: production
28+
WARNING: Do not use the development server in a production environment.
29+
Use a production WSGI server instead.
30+
* Debug mode: off
31+
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
32+
```
33+
34+
现在打开浏览器,访问 <http://localhost:5000> 即可访问我们的程序主页,并看到我们在程序里返回的问候语,如下图所示:
35+
36+
![主页](../docs/flask_images/2-1.png)
37+
38+
执行 `flask run` 命令时,Flask 会使用内置的开发服务器来运行程序。这个服务器默认监听本地机的 5000 端口,也就是说,我们可以通过在地址栏输入 <http://127.0.0.1:5000> 或是 <http://localhost:5000> 访问程序。
39+
40+
> **注意** 内置的开发服务器只能用于开发时使用,部署上线的时候要换用性能更好的服务器,我们会在最后一章学习。
41+
42+
## 代码解析
43+
44+
下面我们来分解这个 Flask 程序,了解它的基本构成。
45+
46+
首先我们从 `flask` 包导入 `Flask` 类,通过实例化这个类,创建一个程序对象 `app`
47+
48+
```python
49+
from flask import Flask
50+
app = Flask(__name__)
51+
```
52+
53+
接下来,我们要注册一个处理函数,这个函数是处理某个请求的处理函数,Flask 官方把它叫做视图函数(view funciton),你可以理解为“**请求处理函数**”。
54+
55+
所谓的“注册”,就是给这个函数戴上一个装饰器帽子。我们使用 `app.route()` 装饰器来为这个函数绑定对应的 URL,当用户在浏览器访问这个 URL 的时候,就会触发这个函数,获取返回值,并把返回值显示到浏览器窗口:
56+
57+
```python
58+
@app.route('/')
59+
def hello():
60+
return 'Welcome to My Watchlist!'
61+
```
62+
63+
> **提示** 为了便于理解,你可以把 Web 程序看作是一堆这样的视图函数的集合:编写不同的函数处理对应 URL 的请求。
64+
65+
填入 `app.route()` 装饰器的第一个参数是 URL 规则字符串,这里的 `/`指的是根地址。
66+
67+
我们只需要写出相对地址,主机地址、端口号等都不需要写出。所以说,这里的 `/` 对应的是主机名后面的路径部分,完整 URL 就是 <http://localhost:5000/>。如果我们这里定义的 URL 规则是 `/hello`,那么完整 URL 就是 <http://localhost:5000/hello>
68+
69+
整个请求的处理过程如下所示:
70+
71+
1. 当用户在浏览器地址栏访问这个地址,在这里即 <http://localhost:5000/>
72+
2. 服务器解析请求,发现请求 URL 匹配的 URL 规则是 `/`,因此调用对应的处理函数 `hello()`
73+
3. 获取 `hello()` 函数的返回值,处理后返回给客户端(浏览器)
74+
4. 浏览器接受响应,将其显示在窗口上
75+
76+
77+
## 实验时间
78+
79+
在这个小节,我们可以通过做一些实验,来扩展和加深对本节内容的理解。
80+
81+
### 修改视图函数返回值
82+
83+
首先,你可以自由修改视图函数的返回值,比如:
84+
85+
```python
86+
@app.route('/')
87+
def hello():
88+
return u'欢迎来到我的 Watchlist!'
89+
```
90+
91+
返回值作为响应的主体,默认会被浏览器作为 HTML 格式解析,所以我们可以添加一个 HTML 元素标记:
92+
93+
```python
94+
@app.route('/')
95+
def hello():
96+
return '<h1>Hello Totoro!</h1><img src="http://helloflask.com/totoro.gif">'
97+
```
98+
99+
保存修改后,只需要在浏览器里刷新页面,你就会看到页面上的内容也会随之变化。
100+
101+
![2-2](../docs/flask_images/2-2.png)
102+
103+
### 修改 URL 规则
104+
105+
另外,你也可以自由修改传入 `app.route` 装饰器里的 URL 规则字符串,但要注意以斜线 `/` 作为开头。比如:
106+
107+
```python
108+
@app.route('/home')
109+
def hello():
110+
return 'Welcome to My Watchlist!'
111+
```
112+
113+
保存修改,这时刷新浏览器,则会看到一个 404 错误提示,提示页面未找到(Page Not Found)。这是因为视图函数的 URL 改成了 `/home`,而我们刷新后访问的地址仍然是旧的 `/`。如果我们把访问地址改成 <http://localhost:5000/home>,就会正确看到返回值。
114+
115+
一个视图函数也可以绑定多个 URL,这通过附加多个装饰器实现,比如:
116+
117+
```python
118+
@app.route('/')
119+
@app.route('/index')
120+
@app.route('/home')
121+
def hello():
122+
return 'Welcome to My Watchlist!'
123+
```
124+
125+
现在无论是访问 <http://localhost:5000/><http://localhost:5000/home> 还是 <http://localhost:5000/index> 都可以看到返回值。
126+
127+
在前面,我们之所以把传入 `app.route` 装饰器的参数称为 URL 规则,是因为我们也可以在 URL 里定义变量部分。比如下面这个视图函数会处理所有类似 `/user/<name>` 的请求:
128+
129+
```python
130+
@app.route('/user/<name>')
131+
def user_page(name):
132+
return 'User page'
133+
```
134+
135+
不论你访问 <http://localhost:5000/user/greyli>,还是 <http://localhost:5000/user/peter>,抑或是 <http://localhost:5000/user/甲>,都会触发这个函数。通过下面的方式,我们也可以在视图函数里获取到这个变量值:
136+
137+
```python
138+
from flask import escape
139+
140+
@app.route('/user/<name>')
141+
def user_page(name):
142+
return 'User: %s' % escape(name)
143+
```
144+
145+
> **注意** 用户输入的数据会包含恶意代码,所以不能直接作为响应返回,需要使用 Flask 提供的 escape() 函数对 name 变量进行转义处理,比如把 `<` 转换成 `&lt;`。这样在返回响应时浏览器就不会把它们当做代码执行。
146+
147+
### 修改视图函数名?
148+
149+
最后一个可以修改的部分就是视图函数的名称了。首先,视图函数的名字是自由定义的,和 URL 规则无关。和定义其他函数或变量一样,只需要让它表达出所要处理页面的含义即可。
150+
151+
除此之外,它还有一个重要的作用:作为代表某个路由的端点(endpoint),同时用来生成 URL。对于程序内的 URL,为了避免手写,Flask 提供了一个 `url_for` 函数来生成 URL,它接受的第一个参数就是端点值,默认为视图函数的名称:
152+
153+
```python
154+
from flask import url_for, escape
155+
156+
# ...
157+
158+
@app.route('/')
159+
def hello():
160+
return 'Hello'
161+
162+
@app.route('/user/<name>')
163+
def user_page(name):
164+
return 'User: %s' % escape(name)
165+
166+
@app.route('/test')
167+
def test_url_for():
168+
# 下面是一些调用示例(请在命令行窗口查看输出的 URL):
169+
print(url_for('hello')) # 输出:/
170+
# 注意下面两个调用是如何生成包含 URL 变量的 URL 的
171+
print(url_for('user_page', name='greyli')) # 输出:/user/greyli
172+
print(url_for('user_page', name='peter')) # 输出:/user/peter
173+
print(url_for('test_url_for')) # 输出:/test
174+
# 下面这个调用传入了多余的关键字参数,它们会被作为查询字符串附加到 URL 后面。
175+
print(url_for('test_url_for', num=2)) # 输出:/test?num=2
176+
return 'Test page'
177+
```
178+
179+
实验过程中编写的代码可以删掉,也可以保留,但记得为根地址返回一行问候,这可是我们这一章的任务。

04_flask/02_Flask模板.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# 第 2 章:模板
2+
3+
在一般的 Web 程序里,访问一个地址通常会返回一个包含各类信息的 HTML 页面。因为我们的程序是动态的,页面中的某些信息需要根据不同的情况来进行调整,比如对登录和未登录用户显示不同的信息,所以页面需要在用户访问时根据程序逻辑动态生成。
4+
5+
我们把包含变量和运算逻辑的 HTML 或其他格式的文本叫做**模板**,执行这些变量替换和逻辑计算工作的过程被称为**渲染**,这个工作由我们这一章要学习使用的模板渲染引擎——Jinja2 来完成。
6+
7+
按照默认的设置,Flask 会从程序实例所在模块同级目录的 templates 文件夹中寻找模板,我们的程序目前存储在项目根目录的 app.py 文件里,所以我们要在项目根目录创建这个文件夹:
8+
9+
```bash
10+
$ mkdir templates
11+
```
12+
13+
## 模板基本语法
14+
15+
在社交网站上,每个人都有一个主页,借助 Jinja2 就可以写出一个通用的模板。
16+
17+
Jinja2 的语法和 Python 大致相同,你在后面会陆续接触到一些常见的用法。在模板里,你需要添加特定的定界符将 Jinja2 语句和变量标记出来,下面是三种常用的定界符:
18+
19+
- `{{ ... }}` 用来标记变量。
20+
- `{% ... %}` 用来标记语句,比如 if 语句,for 语句等。
21+
- `{# ... #}` 用来写注释。
22+
23+
模板中使用的变量需要在渲染的时候传递进去,具体我们后面会了解。
24+
25+
## 编写主页模板
26+
27+
我们先在 templates 目录下创建一个 index.html 文件,作为主页模板。主页需要显示电影条目列表和个人信息,代码如下所示:
28+
29+
*templates/index.html:主页模板*
30+
31+
```jinja2
32+
<!DOCTYPE html>
33+
<html lang="en">
34+
<head>
35+
<meta charset="utf-8">
36+
<title>{{ name }}'s Watchlist</title>
37+
</head>
38+
<body>
39+
<h2>{{ name }}'s Watchlist</h2>
40+
{# 使用 length 过滤器获取 movies 变量的长度 #}
41+
<p>{{ movies|length }} Titles</p>
42+
<ul>
43+
{% for movie in movies %} {# 迭代 movies 变量 #}
44+
<li>{{ movie.title }} - {{ movie.year }}</li> {# 等同于 movie['title'] #}
45+
{% endfor %} {# 使用 endfor 标签结束 for 语句 #}
46+
</ul>
47+
<footer>
48+
<small>&copy; 2018 <a href="http://helloflask.com/tutorial">HelloFlask</a></small>
49+
</footer>
50+
</body>
51+
</html>
52+
```
53+
54+
为了方便对变量进行处理,Jinja2 提供了一些过滤器,语法形式如下:
55+
56+
```jinja2
57+
{{ 变量|过滤器 }}
58+
```
59+
60+
左侧是变量,右侧是过滤器名。比如,上面的模板里使用 `length` 过滤器来获取 `movies` 的长度,类似 Python 里的 `len()` 函数。
61+
62+
> **提示** 访问 <http://jinja.pocoo.org/docs/2.10/templates/#list-of-builtin-filters> 查看所有可用的过滤器。
63+
64+
## 准备虚拟数据
65+
66+
为了模拟页面渲染,我们需要先创建一些虚拟数据,用来填充页面内容:
67+
68+
*app.py:定义虚拟数据*
69+
70+
```python
71+
name = 'Grey Li'
72+
movies = [
73+
{'title': 'My Neighbor Totoro', 'year': '1988'},
74+
{'title': 'Dead Poets Society', 'year': '1989'},
75+
{'title': 'A Perfect World', 'year': '1993'},
76+
{'title': 'Leon', 'year': '1994'},
77+
{'title': 'Mahjong', 'year': '1996'},
78+
{'title': 'Swallowtail Butterfly', 'year': '1996'},
79+
{'title': 'King of Comedy', 'year': '1999'},
80+
{'title': 'Devils on the Doorstep', 'year': '1999'},
81+
{'title': 'WALL-E', 'year': '2008'},
82+
{'title': 'The Pork of Music', 'year': '2012'},
83+
]
84+
```
85+
86+
## 渲染主页模板
87+
88+
使用 `render_template()` 函数可以把模板渲染出来,必须传入的参数为模板文件名(相对于 templates 根目录的文件路径),这里即 `'index.html'`。为了让模板正确渲染,我们还要把模板内部使用的变量通过关键字参数传入这个函数,如下所示:
89+
90+
*app.py:返回渲染好的模板作为响应*
91+
92+
```python
93+
from flask import Flask, render_template
94+
95+
# ...
96+
97+
@app.route('/')
98+
def index():
99+
return render_template('index.html', name=name, movies=movies)
100+
```
101+
102+
为了更好的表示这个视图函数的作用,我们把原来的函数名 `hello` 改为 `index`,意思是“索引”,即主页。
103+
104+
在传入 `render_template()` 函数的关键字参数中,左边的 `movies` 是模板中使用的变量名称,右边的 `movies` 则是该变量指向的实际对象。这里传入模板的 `name` 是字符串,`movies` 是列表,但能够在模板里使用的不只这两种 Python 数据结构,你也可以传入元组、字典、函数等。
105+
106+
`render_template()` 函数在调用时会识别并执行 index.html 里所有的 Jinja2 语句,返回渲染好的模板内容。在返回的页面中,变量会被替换为实际的值(包括定界符),语句(及定界符)则会在执行后被移除(注释也会一并移除)。
107+
108+
现在访问 <http://localhost:5000/> 看到的程序主页如下图所示:
109+
110+
![主页电影列表](../docs/flask_images/3-1.png)

0 commit comments

Comments
 (0)