最近在看辉哥的《Flask Web 开发实战》,这才有了《Flask Web 开发指南》系列的文章,偏向学习笔记多一点,也有实战的内容
看下这个系列的文章我能写多少篇
愚人节玩笑
愚人节大家都喜欢开玩笑来整蛊别人以便达到娱乐效果,但对于开发者来说,就有可能出现让人意想不到的情况
2010 年 4 月 1 日,Armin Ronacher 在网上发表了一篇关于”下一代 Python 微框架“的文章,文章指出这个 Denied 框架不依赖 Python 标准库,只需要复制一份 deny.py 放到你的项目文件夹就可以开始编程
为了让这个玩笑更加可信,看上去更加真实,Armin Ronacher 不但请朋友录制了一个演示视频,还找了几位 Python 程序员为其背书
随着作者一本正经的介绍、示例代码以及演示视频,许多人都信以为真,视频和网站浏览量飞快增长
开发者们对这个项目的认真程度,促使 Armin Ronacher 决定将他的玩笑话落地实现
5 天后,Flask 诞生
有兴趣的可以去看一下 Armin Ronacher 关于这个愚人节玩笑的文章
April 1st Post Mortem | Armin Ronacher's Thoughts and Writings (pocoo.org)
初识 Flask
Flask 官方文档:Welcome to Flask — Flask Documentation (2.2.x) (palletsprojects.com)
Flask 是 Python 编写的 Web 微框架,Web 框架可以让我们不用关心系统底层的请求响应处理,更加方便高效地开发 Web 程序
之所以称 Flask 是微框架,是因为 Flask 核心简单且易于拓展。不但如此,Flask 只保留了 Web 开发的核心功能,想要实现其他功能则需要外部扩展来实现(数据库操作、表单认证、文件上传等),甚至可以自己手动定制开发
Flask 有两个主要依赖:
- Werkzeug——WSGI工具集
1.1. WSGI(Web Server Gateway Interface):Python 中用来规定 Web 服务器如何与 Python Web 程序沟通 - Jinja2
2.1. Jinja2 模板(template),用于渲染页面
前期准备
Python 版本
推荐使用最新版本的 Python 3 。 Flask 支持 Python 3.4 及更高版本的 Python 3 、 Python 2.7 和 PyPy
依赖
当安装 Flask 时,以下配套软件会被自动安装
- Werkzeug 用于实现 WSGI ,应用和服务之间的标准 Python 接口。
- Jinja 用于渲染页面的模板语言。
- MarkupSafe 与 Jinja 共用,在渲染页面时用于避免不可信的输入,防止注入攻击。
- ItsDangerous 保证数据完整性的安全标志数据,用于保护 Flask 的 session cookie.
- Click 是一个命令行应用的框架。用于提供
flask
命令,并允许添加自定义 管理命令
创建并激活虚拟环境
在 Python 中,虚拟环境就是隔离的 Python 解释器环境,为什么要用虚拟环境
因为随着你的 Python 项目越来越多,就会发现不同的项目需要依赖不同版本的库或者 Python 版本
例如你的项目A,使用的是 Python 2,你的项目B使用的是 Python 3
而虚拟环境可以为每一个项目安装独立的 Python 库,这样就可以隔离不同项目之间的 Python 库,也可以隔离项目与操作系统之间的 Python 库
使用虚拟环境,就可以保证你全局 Python 解释器环境的干净,避免包和版本的错乱
pipenv 是基于 pip 的 Python 包管理工具,可以看成是 pip 的加强版,它是 pip、Pipfile 和 Virtualenv 的结合体
接着创建你的虚拟环境,首先进入到你项目的文件夹里面,我的项目放在了D:\helloflask
下
然后使用 pipenv install
命令为当前项目创建虚拟环境
pipenv install
默认情况下,pipenv 会统一管理所有的虚拟环境
- 在 Windows 系统中,虚拟环境文件夹存放在
C:\Users\Administrator\.virtualenvs\
目录下 - 在 Linux 系统中,虚拟环境文件夹存放在
~/.local/share/virtualenvs
目录下
如果你想将虚拟环境文件夹存放到你的项目文件夹里面,可以设置环境变量
#Windows
set PIPENV_VENV_IN_PROJECT=1
#Linux
export PIPENV_VENV_IN_PROJECT=1
激活你的虚拟环境
- 方法一:执行 pipenv shell 命令显式激活
这时 pipenv 会启动一个激活虚拟环境的子 shell,你会发现命令行提示符前面添加了虚拟环境名
输 exit 退出
- 方法二:pipenv run 隐式激活
这个方法允许你不显式激活虚拟环境即可在当前项目的虚拟环境中执行命令
pipenv run python hello.py
安装 Flask
创建并激活虚拟环境之后,我们来安装 Flask
D:\helloflask>pipenv install flask
可以看到我们该项目的虚拟环境文件夹里已经有了 Flask 以及依赖包
pipenv 会自动帮我们管理虚拟环境,所以使用 pipenv install 安装 Python 包时不需要关心是否激活虚拟环境,pipenv 会负责将包安装到虚拟环境中只有需要在全局环境下操作(安装、更新、卸载)包,我们才使用 pip
Pycharm 编辑器
- 打开项目
- 设置 Python 解释器
我们需要手动使用 pipenv 来安装依赖,同时还需要为项目设置正确的 Python 解释器,操作步骤如下:
左上角点击 File ——> Settings
打开 Python 解释器设置窗口
找到该项目的虚拟环境文件夹路径(pipenv --venv 可以查看)
D:\helloflask>pipenv --venv
C:\Users\Administrator\.virtualenvs\helloflask-hUtz0ICQ
设置之后,在 Pycharm 打开一个 Terminal 会话,你会发现命令行提示符前出现虚拟环境名称,说明虚拟环境已经激活,以后每次打开项目,Pycharm 都会帮你自动激活虚拟环境,并且把你的工作目录定位到项目的根目录
Hello,Flask!
在项目根目录下创建 demo 文件夹,在 demo 下创建 myflask 文件夹,进入myflask 然后添加 hello.py(不要命名为 flask.py,会和 Flask 本身冲突)
我们来编写一个 Flask 程序
import flask
app = flask.Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello,Flask!</h1>'
首先 import flask
导入 flask 包,然后 从 flask 包导入 Flask 类,这个类表示一个 Flask 程序,app = flask.Flask(__name__)
表示实例化这个 Flask 类并用 app 去接收它
我们知道,一个 Web 应用程序中,client 和 server 的交互过程如下:
- 用户在浏览器输入 URL 访问某个资源
- Flask 接收用户请求并分析 URL
- 找到 URL 对应的处理函数(视图函数)
- 执行对应函数并生成响应,返回给浏览器
视图函数
接下来便是注册一个处理函数,这个函数专门负责处理某个请求,Flask 官方把它叫做视图函数
所谓“注册”,就是给这个函数加上一个装饰器,我们使用 app.route()
装饰器来为这个函数绑定对应的 url,当用户在浏览器访问这个 URL 的时候,就会触发这个函数,浏览器窗口就会显示这个函数的返回值
@app.route('/')
def index():
return '<h1>Hello,Flask!</h1>'
我们只需要写出相对地址,主机地址、端口号等都不需要写出。所以说,这里的 /
对应的是主机名后面的路径部分,完整 URL 就是 http://localhost:5000/。如果我们这里定义的 URL 规则是 /hello
,那么完整 URL 就是 http://localhost:5000/hello
整个请求的处理过程如下:
- 用户在浏览器访问http://localhost:5000/
- 服务器解析请求,发现请求的 URL 匹配到了 ‘/’,调用对应函数
index()
- 获取
index()
函数的返回值,处理后返回给浏览器 - 浏览器接收并解析响应,将其信息显示在窗口上
我们还可以这个视图函数绑定多个 URL(即一个视图函数可以绑定多个URL)
@app.route('/')
@app.route('/index')
@app.route('/home')
def index():
return '<h1>Hello,Flask!</h1>'
现在无论是访问 http://localhost:5000/
、http://localhost:5000/home
还是 http://localhost:5000/index
,返回的都是同一个请求结果
URL 规则
我们知道,Flask 通过 app.route() 来把视图函数绑定到 URL,而传入 app.route
装饰器的参数,称之为 URL 规则
之所以称之为规则,是因为我们可以在这个 URL 参数里面定义变量部分,实现动态 URL
@app.route('/user/<name>')
def user_page(name):
return '<h1>Hello,%s!</h1>' % name
不论你访问 http://localhost:5000/user/xianyu
,还是 http://localhost:5000/user/edison
,抑或是 http://localhost:5000/user/kanye
,都会触发这个视图函数
而且这个视图返回的响应会随着请求的 URL 中的 name 变量而变化
但如果你的视图函数传进入的 URL 规则有变量,而用户访问的 URL 中没有变量时,就会返回 404 错误响应
我们可以在 app.route
装饰器中使用 default 参数设置 URL 变量的默认值
import escape
#为 user 视图新添加一个装饰器,添加默认值
@app.route('/user', defaults={'name': 'Programmer'}))
@app.route('/user/<name>')
def user_page(name):
return f'User: {markupsafe.escape(name)}'
用户输入的数据会包含恶意代码,所以不能直接作为响应返回需要使用 MarkupSafe(Flask 的依赖之一)提供的 escape() 函数对 name 变量进行转义处理
比如把 < 转换成 \<。这样在返回响应时浏览器就不会把它们当做代码执行
如果用户访问 /user ,那么变量 name 就会使用默认值 Programmer
上面用法等同于如下函数
@app.route('/user)
@app.route('/user/<name>')
def user_page(name='Programmer'):
return f'User: {markupsafe.escape(name)}'
Run,Flask!
Flask 通过依赖包 Click 内置了一个命令行交互界面系统
我们可以通过 Flask 命令执行内置命令,其中 flask run 用来启动程序
打开 Terminal 终端,进入到与 hello.py 同级目录下
#执行命令
(helloflask) D:\helloflask\demo>flask run
打开浏览器访问 URL
flask run 命令是如何找到我们的程序的呢?
一般来讲,根据 Flask 自动发现程序机制来讲,步骤如下:
- 从当前目录寻找 app.py 或 wsgi.py,并从中寻找名为 app 或 application 的程序实例
- 从环境变量 FLASK_APP 对应的值寻找名为 app 或 application 的程序实例
那如果我们的程序不叫 app.py,叫 hello.py、wtf.py ,Flask 该咋发现呢?
比如说我当前项目结构如下
- 方法一
设置环境变量 FLASK_APP的值为程序名字
#windows
set FLASK_APP=myflask/hello
#linux
export FLASK_APP=myflask/hello
然后再执行 flask run 启动程序
- 方法二(建议)
我们安装 python-dotenv,在执行 flask run 命令或者其他命令的时候,程序自动从 .falskenv
或 .env
文件加载变量
我们首先安装 python-dotenv 到虚拟环境
#在项目根目录下打开 cmd 窗口
D:\helloflask>pipenv install python-dotenv
接着在项目根目录下创建.falskenv
和 .env
文件
.flaskenv 用来存储 Flask 命令行系统相关的公开环境变量;.env 则用来存储敏感数据
在新创建的 .flaskenv 文件里,我们添加如下内容
FLASK_APP=myflask/hello
FLASK_DEBUG=True
FLASK_APP=myflask/hello
表明我们的程序存放在 myflask 目录下
FLASK_DEBUG=True
表明是开发调试模式
然后再执行 flask run 启动程序,启动成功!
(helloflask) D:\helloflask\demo>flask run
* Serving Flask app 'myflask/hello'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000