0%

Flask 初探

最近为了写一个微信小程序的后端,接触了 Flask 这个框架,阅读了官方文档和一些博文,我认为官方文档写的非常不错,很适合入门。这一周也写了很多 Flask 代码,但由于我没有系统学习过 Python,所以在阅读文档时候遇到了一些与 Python 相关的问题,在这里记录下来,可以作为对 Python 初学者阅读 Flask 文档的一种补充。

创建虚拟环境

无论开发什么 Python 项目,不论其大小,都应该养成创建虚拟环境的好习惯(就像习惯使用版本控制一样),来隔离不同项目的 Python 库。在创建项目文件夹后,用下面的命令来创建并激活虚拟环境,激活后就可以安装项目需要的库了,比如 Flask!

1
2
3
python -m venv venv
venv\Scripts\activate
pip install Flask

下面解释一下 python -m venv venv

python main.py args 类似,python -m venv venv 执行 venv.py 这个模块,但 switch -m 允许 Python 执行不在当前目录的模块。对于可以通过 import module_name 引入的模块,大都可以通过 python -m 执行,而不用写出模块的具体路径。

装饰器

在 Flask 中要为不同的 URL 编写对应的响应,可以通过装饰器实现,例如访问主页时,想要让页面显示 Hello World

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

@app.route('/index')
def index():
return 'Hello World'

装饰器其实就是一种函数,更具体来说是一种高阶函数,它的返回值也是一个函数,作用是给被装饰的函数增加一些功能,比如这里的 @app.route('/index') 其实是 index = app.route('/index')(index) 的语法糖,函数 index 被传入装饰器,装饰器返回装饰后的函数并赋值给 index。结果时,被装饰后的 index 获得了一些新的功能,例如当 /index 被访问时,执行这个 index

调试模式

在开发时,应该开启调试模式来让一切更方便快捷,调试模式提供了热更新和一个 debugger。通过设置环境变量的方法开启调试模式:

1
2
set FLASK_ENV=development
flask run

但切记不要在生产环境中使用,因为 debugger 允许执行任意的 Python 代码。

与请求打交道

当你想获取与客户端请求相关的东西时,你总能在 reuqest 对象里找到,例如:

  • 请求的方法是 request.method
  • 请求的表单是 request.form,是一个字典,表单名是 key
  • URL 里的查询字段(?key=value)是 request.args.get('key', '')
  • 文件是 request.files,是一个字典,文件名是 key
  • Cookie 是 request.cookies,是一个字典

查询参数是字典类型的,访问它时,最佳实践是用 get(key, default) 的方式而非 [],这样可以避免用户的查询 key 有错时看到 400。

文件对象是继承自 Python 标准的 file 对象,FLask 为其添加了一些方法,如 save() 方法可以将文件保存到文件系统上。

永远不要相信用户的输入

Flask 在处理用户输入的问题上为我们提供了许多帮助,如在通过 Jinja 模板写 HTML 时,用户输入是会被自动转义(automatic escaping)的。但在没有使用 Jinja 模板的时候,如直接返回字符串时,我们可以通过 escape() 方法来转义:

1
2
from markupsafe import escape
ret = 'Logged in as %s' % escape(request.form['username'])

在处理用户上传的文件时,若要通过原文件名保存之,可以通过 secure_filename() 方法来防止恶意文件名:

1
2
from werkzeug.utils import secure_filename
filename = secure_filename(f.filename)

自定义响应

在编写一个请求的响应时,Flask 会帮助你通过返回值构造真正的 HTTP Response,但若你不满足于简单的返回字符串,HTML 或 JSON,你可以通过 make_response() 方法来修改之前的简单响应,如添加自定义 headers 或者设置 cookie,如下面的例子:

原始版本:

1
2
3
@app.route('/')
def index():
return render_template('index.html')

定制化:

1
2
3
4
5
@app.route('/')
def index():
resp = make_response(render_template('index.html'))
resp.headers['X-name'] = 'sichen'
return resp

可以看出操作方法就是把之前的返回值传入 make_response(),然后对 response 对象进行自定义。

杂项

  • 当在程序中需要某个 URL 时,应该使用 url_for() 而不是硬写。
  • python -c "import os; print(os.urandom(16))" 可以生成 Flask.secret_key

参考

Flask Quickstart
Stackoverflow: Python -m
Python 装饰器 By liaoxuefeng

奥里给,老铁们,干了!