Flask的基本原理与核心知识
环境安装
# 多个 Python 版本时安装为指定版本安装 pip
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
python3.6 get-pip.py
pip install pipenv
pipenv install # 安装虚拟环境
pipenv shell # 启动虚拟环境
pipenv install flask ...
pipenv uninstall flask ...
pipenv graph # 打印出所有信息
exit # 退出环境
1
2
3
4
5
6
7
8
9
10
11
12
# 多个 Python 版本时安装为指定版本安装 pip
curlhttps://bootstrap.pypa.io/get-pip.py -o get-pip.py
pythonget-pip.py
python3.6get-pip.py
pipinstallpipenv
pipenvinstall# 安装虚拟环境
pipenvshell# 启动虚拟环境
pipenvinstallflask...
pipenvuninstallflask...
pipenvgraph# 打印出所有信息
exit# 退出环境
# app.run 参数
app.run(debug=True) # 打开调试模式
host='0.0.0.0' # 设置主机 IP
port=5000 # 设置端口
# 路由注册方法
# 1.装饰器
@app.route("/hello")
# 2.add_url_rule
app.add_url_rule('/hello', view_func=hello)
# 导入配置文件(假定为同级 config.py 文件)
app.config.from_object('config')
app.config['XXX'] # 读取,要求 XXX 全部为大写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# app.run 参数
app.run(debug=True)# 打开调试模式
host='0.0.0.0'# 设置主机 IP
port=5000# 设置端口
# 路由注册方法
# 1.装饰器
@app.route("/hello")
# 2.add_url_rule
app.add_url_rule('/hello',view_func=hello)
# 导入配置文件(假定为同级 config.py 文件)
app.config.from_object('config')
app.config['XXX']# 读取,要求 XXX 全部为大写
蓝图
解决分割视图函数后循环导入的问题:
实例化核心对象 app -> 插入blueprint
blueprint -> 插入视图函数、还可包含静态文件夹和模板文件夹
蓝图放在每个包的__init__.py 中进行注册,然后各文件进行导入
from flask import Blueprint
package_name = Blueprint('package_name', __package__)
from web.package_name import xxx
1
2
3
4
5
fromflaskimportBlueprint
package_name=Blueprint('package_name',__package__)
fromweb.package_nameimportxxx
然后在 主 app 目录下的__init__.py 上进行注册:
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object('config')
register_blueprint(app)
return app
def register_blueprint(app):
from app.package_name import package_name
app.register_blueprint(package_name)
1
2
3
4
5
6
7
8
9
10
11
12
fromflaskimportFlask
defcreate_app():
app=Flask(__name__)
app.config.from_object('config')
register_blueprint(app)
returnapp
defregister_blueprint(app):
fromapp.package_nameimportpackage_name
app.register_blueprint(package_name)
参数验证:wtforms
模型:flask-sqlalchemy
Flask 经典错误:RuntimeError: Working outside of application context.
4个核心对象:Flask和AppContext应用上下文、Request和RequestContext请求上下文
这一问题通常出现在单元测试和离线应用中,因为视图函数的请求中 Flask 会替你处理上下文的问题,出现的原因为current_app指向栈顶元素,而由于栈顶为空无法获取到上下文,解决方法是获取应用上下文并压入栈
自己推入应用上下文的主要应用场景为离线应用和单元测试
ctx = app.app_context() # 得到应用上下文
ctx.push() # 入栈
...
ctx.pop()
# 更简洁的写法
with app.app_context():
...
1
2
3
4
5
6
7
8
ctx=app.app_context()# 得到应用上下文
ctx.push()# 入栈
...
ctx.pop()
# 更简洁的写法
withapp.app_context():
...
Ctrl/Cmd+Alt/Option+左/右方向键返回上下层或进入下一层源代码
SQLAlchemy中解决 app上下文的问题:
RuntimeError: No application found. Either work inside a view function or push an application context.
# 方法一
db.init_app(app)
db.create_all(app=app) # 传入 app
# 方法二
db.init_app(app)
with app.app_context():
db.create_all()
# 方法三(初始化时传入)
db = SQLAlchemy(app=app)
1
2
3
4
5
6
7
8
9
10
11
# 方法一
db.init_app(app)
db.create_all(app=app)# 传入 app
# 方法二
db.init_app(app)
withapp.app_context():
db.create_all()
# 方法三(初始化时传入)
db=SQLAlchemy(app=app)
线程
多线程可以充分的利用 CPU 的性能优势,Python GIL 全局解释器锁,对于 CPU 密集型程序多线程鸡肋,对于 IO 密集型程序 Python 的多线程则有意义
import threading
def worker():
print('I am thread')
t = threading.current_thread()
print(t.getName())
t = threading.current_thread()
print(t.getName()) # 主线程MainThread
new_t = threading.Thread(target=worker, name='my_thread') # 这个子线程的默认名称为Thread-1,可通过 name 来指定名称
new_t.start() # 启动线程
1
2
3
4
5
6
7
8
9
10
11
12
13
importthreading
defworker():
print('I am thread')
t=threading.current_thread()
print(t.getName())
t=threading.current_thread()
print(t.getName())# 主线程MainThread
new_t=threading.Thread(target=worker,name='my_thread')# 这个子线程的默认名称为Thread-1,可通过 name 来指定名称
new_t.start()# 启动线程
Flask 使用 Werkzeug 的 Local 和 LocalStack来实现线程隔离
from werkzeug.local import Local, LocalStack
1
fromwerkzeug.localimportLocal,LocalStack
对象序列化
# 普通的直接使用
jsonify(obj.__dict__)
# 但对于对象中还包含对象甚至多层嵌套的:
json.dumps(obj, default=lambda o:o.__dict__)
1
2
3
4
# 普通的直接使用
jsonify(obj.__dict__)
# 但对于对象中还包含对象甚至多层嵌套的:
json.dumps(obj,default=lambdao:o.__dict__)
Jinja2
# url_for
# flash('Test message')
{% set messages = get_flashed_messages() %}
# 限定作用域
{% with messages = get_flashed_messages() %}
{{ messages }}
{% endwith %}
1
2
3
4
5
6
7
8
9
10
11
# url_for
# flash('Test message')
{%setmessages=get_flashed_messages()%}
# 限定作用域
{%withmessages=get_flashed_messages()%}
{{messages}}
{%endwith%}
数据库
pip3 install Flask-Migrate
# migrate = Migrate(app, db)
flask db init
flask db migrate
1
2
3
4
pip3installFlask-Migrate
# migrate = Migrate(app, db)
flaskdbinit
flaskdbmigrate