web开发框架Flask

一、安装

1
pip install Flask

二、快速上手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"

if __name__ == '__main__':
app.run(port=5000, debug=True)

加入动态路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"

@app.route("/user/<name>")
def user(name):
return "<p>Hello, {}!</p>".format(name)

if __name__ == '__main__':
app.run(port=5000, debug=True)

三、请求-响应循环

想要理解Flask的工作模式,就需要理解:请求-响应循环。

请求

请求对象,封装了客户端发出的HTTP请求中的内容。

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

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
user_agent = request.headers.get('User-Agent')
return "<p>your brower is {}</p>".format(user_agent)

if __name__ == '__main__':
app.run(port=5000, debug=True)

响应

我们可以创建一个响应对象,然后设置cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask, request, make_response
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
user_agent = request.headers.get('User-Agent')
return "<p>your brower is {}</p>".format(user_agent)

@app.route("/test")
def test():
response = make_response('<h1>This document carries a cookies!</h1>')
response.set_cookie('answer', '42')
return response

if __name__ == '__main__':
app.run(port=5000, debug=True)

HTTP响应中很重要的一部分是响应状态码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from flask import Flask, request
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
user_agent = request.headers.get('User-Agent')
return "<p>your brower is {}</p>".format(user_agent)

@app.route("/test1")
def test1():
return '<h1>Bad Request</h1>', 400

if __name__ == '__main__':
app.run(port=5000, debug=True)

响应有种特殊的类型称为重定向,用以加载新页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from flask import Flask, request, redirect
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
user_agent = request.headers.get('User-Agent')
return "<p>your brower is {}</p>".format(user_agent)

@app.route("/test2")
def test2():
return redirect('https://www.bytecat.net')

if __name__ == '__main__':
app.run(port=5000, debug=True)

四、响应的进阶:模板

视图函数的作用很明确,即生成请求的响应。在前面的例子中视图函数既包含了业务逻辑,也包含了表现逻辑(html),这种模式对于最简单的请求来说是够了,但是对于大型应用来说是不合理的,因为将业务逻辑和表现逻辑混在一起会导致代码难以理解和维护。
为了提高应用的可维护性,我们需要做一些改进,把表现逻辑移到模板中。

渲染模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, render_template
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
return render_template('index.html')

if __name__ == '__main__':
app.run(port=5000, debug=True)

默认情况下,Flask会在应用的templates子目录中寻找模板。所以需要新建templates子目录,将模板保存在里面。

1
<h1>hello world!</h1>

模板传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, render_template
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
return render_template('index.html')

@app.route("/user/<name>")
def user(name):
return render_template('user.html', name=name)

if __name__ == '__main__':
app.run(port=5000, debug=True)

模板user.html内容如下

1
<h1>hello {{name}}!</h1>

在模板中使用的 结构表示一个变量,这是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取。
Jinja2模板引擎能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。下面是一些示例。

1
2
3
<p>A value from a dictionary: {{ mydict['key'] }}. </p>
<p>A value from a list: {{ mylist[3] }}. </p>
<p>A value from an object's method: {{ myobj.somemethod() }}. </p>

变量的值可以使用过滤器修改。过滤器添加在变量名之后,二者之间以竖线分隔。例如:

1
<h1>hello {{name|capitalize}}!</h1>

这个模板把name变量的值变成首字母大写的形式。下面是Jinja2提供的部分常用的过滤器。

过滤器名 说明
safe 渲染值时不转义
capitalize 把值的首字母转换成答谢,其他字母转换成小写
lower 把值转换成小写形式
upper 把值转换成大写形式
title 把值中每个单词的首字母都转换成大写
trim 把值的首尾空格去掉
striptags 渲染之前把值中所有的html标签都删掉

注意:千万别再不可信的值上使用safe过滤器,例如用户在表单中输入的文本.

控制结构

Jinja2提供了多种控制结构,可用来改变模板的渲染流程。

(1)条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask, render_template
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
return render_template('index.html')

@app.route("/user/<name>")
def user(name):
if name == 'bytecat':
return render_template('user.html', name=name)
else:
return render_template('user.html')

if __name__ == '__main__':
app.run(port=5000, debug=True)

user.html改写如下

1
2
3
4
5
{% if name %}
<h1>hello {{ name|capitalize }}!</h1>
{% else %}
<h1>hello, Stranger!</h1>
{% endif %}

(2)循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from flask import Flask, render_template
from flask_cors import CORS

def create_app():
app = Flask(__name__) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
return render_template('index.html')

@app.route("/user")
def user():
names = ['tom', 'alice', 'victor', 'alex', 'eric']
return render_template('user.html', names=names)

if __name__ == '__main__':
app.run(port=5000, debug=True)

user.html改写如下

1
2
3
4
5
<ul>
{% for name in names %}
<li>{{ name }}</li>
{% endfor %}
</ul>

五、其他

静态文件

web应用不是仅由python代码和模板组成,多数应用还会使用静态文件,例如模板中html代码引用的图像、js和css。
默认设置下,Flask在应用根目录中名为static的子目录中寻找静态文件。如果需要,可在static文件夹中使用子文件夹存放文件。
下面的示例展示了如何在模板中引入favicon.ico图标,这个图标会显示在浏览器的地址栏中。

app.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
from flask import Flask, render_template
from flask_cors import CORS
import os

# 项目根路径
BASE_PATH: str = os.path.dirname((os.path.abspath(__file__)))
print(BASE_PATH)

def create_app():
app = Flask(
__name__,
static_folder=f"{BASE_PATH}/static",
template_folder=f"{BASE_PATH}/templates"
) # 创建app实例
CORS(app, supports_credentials=True) # 设置跨域
return app

app = create_app()

@app.route("/")
def index():
return render_template('index.html')

if __name__ == '__main__':
app.run(port=5000, debug=True)

index.html

1
2
3
4
5
6
7
8
{% block head %}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
{% endblock %}

{% block content %}
<h1>hello world!</h1>
{% endblock %}