学习 flask 笔记,包含官方教程内容及重构时遇到的问题
Create a REST API with Flask (Mac)
安装与环境配置
Create a project folder and a .venv folder within:
1 | $ mkdir flask-demo |
Activate the corresponding environment
1 | $ . .venv/bin/activate |
Install Package
1 | # 安装flask |
示例 Demo
Create a new file app.py, which is same level with .venv
1 | # app.py |
Run the application, and open http://127.0.0.1:5000/
1 | # the second app is the name of your application |
Output requirement file
1 | $ pip freeze > requirement.txt |
If you have a exist requirement.txt, and you want to install all the package
1 | $ pip install -r requirement.txt |
使用内置 SQLite+Jinja+Flask+Python 写一个博客页面
项目结构:这里的项目比较小,只有内置数据库+html 实现,没有专门的前端
步骤:详见官方 Flask 教程
其他需要学习的点:
了解不同项目规模,不同项目结构
了解 instance,config.py 使用
了解不同数据库连接与使用,了解 ORM 在 flask 中的使用
深刻理解 Blueprint
了解前后端分离在 flask 中的使用,比如不用 Jinja,而使用 React
思考优化代码,用户认证代码重构
部署 docker 及其他 devops,了解 flask 应用常规部署方式
了解 pytest
其他补充,详见:explore flask 中译
配置 Config
为了加载配置变量,我通常使用app.config.from_object()。如果是单一模块应用中,是在app.py;或者在yourapp/init.py,如果是基于包的应用。无论在哪种情况下,代码看上去像这样:
1 | from flask import Flask |
instance 文件夹
有时你需要定义一些不能为人所知的配置变量。为此,你会想要把它们从config.py中的其他变量分离出来,并保持在版本控制之外。你可能要隐藏类似数据库密码和 API 密钥的秘密,或定义特定于当前机器的参数。为了让这更加轻松,Flask 提供了一个叫instance 文件夹的特性。instance 文件夹是根目录的一个子文件夹,包括了一个特定于当前应用实例的配置文件。我们不要把它提交到版本控制中。
这是一个使用了 instance 文件夹的简单 Flask 应用的结构:
1 | config.py |
使用 instance 文件夹
要想加载定义在 instance 文件夹中的配置变量,你可以使用app.config.from_pyfile()。如果在调用Flask()创建应用时设置了instance_relative_config=True,app.config.from_pyfile()将查看在instance文件夹的特殊文件。
1 | app = Flask(__name__, instance_relative_config=True) |
现在,你可以在instance/config.py中定义变量,一如在config.py。你也应该将 instance 文件夹加入到版本控制系统的忽略名单中。比如假设你用的是 git,你需要在gitignore中新开一行,写下instance/。
密钥
instance 文件夹的隐秘属性使得它成为藏匿密钥的好地方。你可以在放入应用的密钥或第三方的 API 密钥。假如你的应用是开源的,或者将会是开源的,这会很重要。我们希望其他人去使用他们自己申请的密钥。
1 | # instance/config.py |
最小化依赖于环境的配置
如果你的生产环境和开发环境之间的差别非常小,你可以使用你的 instance 文件夹抹平配置上的差别。在instance/config.py中定义的变量可以覆盖在config.py中设定的值。你只需要在app.config.from_object()之后才调用app.config.from_pyfile()。这样做的其中一个优点是你可以在不同的机器中修改你的应用的配置。你的开发版本库可能看上去像这样:
config.py
1 | DEBUG = False |
instance/config.py
1 | DEBUG = True |
然后在生产环境中,你将这些代码从instance/config.py中移除,它就会改用回config.py中设定的变量。
依照环境变量来配置
instance 文件夹不应该在版本控制中。这意味这你将不能追踪你的 instance 配置。在只有一两个变量的情况下这不是什么问题,但如果你有关于多个环境(生产,稳定,开发,等等)的一大堆配置,你不会愿意冒失去它们的风险。
Flask 给我们提供了根据环境变量选择一个配置文件的能力。这意味着我们可以在我们的版本库中有多个配置文件,并总是能根据具体环境,加载到对的那个。
当我们到了有多个配置文件共存的境况,是时候把文件都移动到config包之下。下面是在这样的一个版本库中大致的样子:
1 | requirements.txt |
在我们有一些不同的配置文件的情况下,可以这样设置:
| 文件名 | 内容 |
|---|---|
| config/default.py | 默认值,适用于所有的环境或交由具体环境进行覆盖。举个例子,在config/default.py中设置DEBUG = False,在config/development.py中设置DEBUG = True。 |
| config/development.py | 在开发环境中用到的值。这里你可以设定在 localhost 中用到的数据库 URI 链接。 |
| config/production.py | 在生产环境中用到的值。这里你可以设定数据库服务器的 URI 链接,而不是开发环境下的本地数据库 URI 链接。 |
| config/staging.py | 在你的开发过程中,你可能需要在一个模拟生产环境的服务器上测试你的应用。你也许会使用不一样的数据库,想要为稳定版本的应用替换掉一些配置。 |
要在不同的环境中指定所需的变量,你可以调用app.config.from_envvar():
1 | # yourapp/__init__.py |
app.config.from_envvar(‘APP_CONFIG_FILE’)将加载由环境变量APP_CONFIG_FILE指定的文件。这个环境变量的值应该是一个配置文件的绝对路径。
这个环境变量的设定方式取决于你运行你的应用的平台。如果你是在一台标准的 Linux 服务器上运行,你可以使用一个 shell 脚本来设置环境变量并运行run.py。
start.sh
1 | APP_CONFIG_FILE=/var/www/yourapp/config/production.py |
start.sh特定于某个环境,所以它也不能放入版本控制当中。如果你把应用托管到 Heroku,你可以用 Heroku 提供的工具设置环境变量参数。对于其他 PAAS 平台也是同样的处理。
总结
- 一个简单的应用也许仅需一个配置文件:config.py
- instance 文件夹可以帮助我们隐藏不愿为人所知的配置变量。
- instance 文件夹可以用来改变特定环境下的程序配置。
- 应对复杂的,基于环境的配置,我们可以结合环境变量和
app.config.from_envvar()来使用。
使用 React+Flask+PostgreSQL+SQLAlchemy+Docker 写博客页面
待补充 …
Fundemental
Routing
在链接中使用变量,可以在 URL 使用<variable_name>,变量前可以指定变量类型
1 | #这里的 int 可写可不写 |
Unique URLs / Redirection Behavior
两种,
项目 URL 可以是/project/,如果输入/project会重定向到/project/
端点 URL 是/about,如果输入/about/会报 404 错误
1 |
|
URL Building
示例:
1 | from flask import Flask, url_for, redirect, render_template_string |
避免硬编码 URL
1 | <!-- 硬编码,路径一改全都要改 --> |
集中管理路由
- 当你在
@app.route('/u/<int:user_id>')改为@app.route('/member/<int:user_id>'),只需改这处定义,所有使用url_for('show_profile', user_id=…)的链接自动跟着更新。
自动拼接查询参数 & 处理斜杠
1 | url_for('search', q='Flask', page=2) |
- 省去手动拼接
?q=…&page=…的繁琐,且能正确 URL-encode。
支持蓝图 & 多模块
1 | # blueprint user 注册时 name='user' |
- 蓝图名 + 视图名自动拼接,不用自己去记 URL 层级。
HTTP Method
两种
一种使用 route() + method
1 | from flask import request |
一种使用单独的 get(), post() 方法
1 |
|
默认情况下,一个路由只响应 GET 请求。
其他详见:QuickStart
报错
问题一:terminal 输入pip3 install Flask 报错
1 | WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1018)'))': /simple/flask/ |

解决:
1 | # 更新pip |
验证:
1 | $ pip freeze |
问题二:Access to 127.0.0.1 was denied
解决:open chrome://net-internals/#sockets,click [Flush socket pools], refresh your website.
问题三:运行 flask –app flaskr run –debug 时报错
Usage: flask run [OPTIONS] Try ‘flask run –help’ for help. Error: Failed to find Flask application or factory in module ‘flaskr’. Use ‘flaskr:name’ to specify one.
解决:重开一个新项目,写好代码后重新跑,不再报错
问题四:运行 pytest,报错 ModuleNotFoundError: No module named
1 | ImportError while loading conftest '/Users/ella/Documents/Code/Demo/flask-api/tests/conftest.py'. |
解决:在 conftest.py 中添加下面代码:
1 | import sys |
原因:在 cmd 或者 terminal 控制台中直接使用 python 相关命令来执行程序,不会自动将当前项目加入到 PYTHONPATH 环境变量下,如果涉及到 import 其他文件夹下的变量就会报类似 ImportError: No module named xxx 这样的错误。
解决方法是使用 sys.append() 命令把报警包的所在文件夹路径加入到 PYTHONPATH。详见:ModuleNotFoundError: No module named ‘xxx’可能的解决方案大全