从Flask-Script迁移到Flask-Cli
Abstrct
flask从0.11版本开始引入了click提供命令行支持,在此之前我们通常会引入Flask-Script来提供。
在《Flask web开发》这本书编写时flask0.11还没有发布,因此书中仍然以flask-script提供命令行支持。因此在flask0.11发布一年后,作者写了这篇文章来帮助大家从flask-script迁移到Flask-Cli,该博文便是作者这篇文章的翻译。
作者对于Click引入flask的意见
回到2014年,当Armin Ronacher向我介绍将Click整合进flask,我是(现在也是)拒绝的,这给Flask内核项目添加了别的依赖,我建议基于click实现命令行支持作为flask的拓展,与flask-script进行公平的竞争。你可以查看该讨论在GitHub的issue中 https://github.com/smurfix/flask-script/issues/97。
因此我确信,强制命令行工具基于Click是个错误,并且违反了flask的基本准则‘将最优秀的工具用于每一项任务’ 。而且不幸的是,click成为flask核心的一部分使flask-script的维护者离开了,而且从github的repository来看,这个项目似乎正在缓慢死亡
那么,flask-script有什么问题呢?
flask确实有着一个重要但是同时却足够有趣的缺陷,由于早期设计的flask reloader的问题,你将直接使用app.run()启动你的应用而不是Flask-Script
如果你以debug模式启动flask,那么将有两个flask进程被运行。第一个进程(我们可以称他为watcher)将会观察源代码的运行,第二个进程才是实际的flask服务器。当任何文件被修改时,这个watcher一旦观察到文件改变将会kill服务进程,然后启动一个使用已经更新的源代码的服务器进程。当你更新的某个源文件中存在语法错误时,会出现一个问题。Watcher进程并不知道源码是否更好,它会kill旧的服务器进程,运行一个新的服务器进程。但是新的服务器进程却不会运行成功,因为python解析修改后的文件时会抛出错误。当服务进程存在在错误时,这个watcher进程也会退出,直到你修复了bug并重启。
在你使用新的命令flask run命令行时load将会很完美,直到你第一个request发来之前,应用都不会被加载,当引入源码文件有错误时,他将会被在运行时处理,这意味着你可以使用基于web的debug工具。新的watcher进程也更加智能,在服务端被kill后仍然会坚持监控源码的变化,并在源码发生改变之后重启服务。
新的Flask-CLi
Flask-Cli比Flask-Script更加优秀吗?让我们回顾下新的Flask应用提供的默认命令吧
当你安装Flask0.11或者更新的版本后,你的环境变量将会存在flask命令
(venv) $ flask
Usage: flask [OPTIONS] COMMAND [ARGS]...
This shell command acts as general utility script for Flask applications.
It loads the application configured (through the FLASK_APP environment
variable) and then provides commands either provided by the application or
Flask itself.
The most useful commands are the "run" and "shell" command.
Example usage:
$ export FLASK_APP=hello.py
$ export FLASK_DEBUG=1
$ flask run
Options:
--version Show the flask version
--help Show this message and exit.
Commands:
run Runs a development server.
shell Runs a shell in the app context.
当我们使用Flask-Script时,你将创建名为manage.py的驱动脚本。我们来看下flask-script与flask-cli之间的对比
#flask-script -> flask-Cli
./manage.py runserver -> flask run
./manage.py shell ->flask shell
看上去似乎没什么区别。
然和事实上,manage.py和flask发现我们Flask应用实例的方式是完全不一样的。对于Flask-Script提供了Manager类直接在我们的应用工厂中使用。然和新的Flask-Cli却没用提供应用实例而是设定FLASK_APP的环境变量,一般用来设定文件名或者模块名。FLask将会寻找模块中的app或者application的实例来使用。
可惜,Flask-Cli没有直接为工厂函数提供支持,这个方法意味着你如果需要使用工厂函数你必须定义一个工厂函数模块来创建你的app对象,然后再FLASK_APP中引用。这与wsgi.py模块在Django中的概念是一致的
如果你想为Flasky应用提供FLask Cli的支持,你可以在flasky.py中这样编写
import os
from app import create_app
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
我们在将会会完全迁移至新的Cli,不在使用manage.py来。
Windows设置FLASK_APP
set FLASK_APP = flasky.py
flask run
flask run命令提供了配置来启用、禁用reloader和debugger,当然你也可以设置IP 的address和port来控制服务器的监听。这些配置虽然与Flask-Script相近但并不完全相同,可以使用flask run -help
来查看提供的配置。
大部分应用可以使用下面的方式启动
if __name__ == '__main__':
app.run()
当你不需要使用CLI支持时你确实可以以这种方式启动。但是当你确实需要新的cli时,你尽可以移除它。
使用Flask Shell 命令
shell命令基本上是相同的,但是在如何定义要自动导入shell上下文中的其他symbols有轻微的差别。这个功能可以节省你在应用程序工作时的大量时间。通常,你在shell中的测试或调试shell中添加model类、数据库实例和其他可能与之交互的对象。
对于FLask-Script,Flasky应用有如下shell上下文定义
def make_shell_context():
return dict(app=app, db=db, User=User, Follow=Follow, Role=Role,
Permission=Permission, Post=Post, Comment=Comment)
manager.add_command("shell", Shell(make_context=make_shell_context))
正如你在上文看到的,make_shell_context()函数被add_command引用来定义shell参数。Flask-Script在启动shell前直接调用这个函数,然后返回一个包含这些symbol的字典。
Flask CLI提供了相同功能,但是确实以decorator(装饰器)来判断是不是shell上下文对象。为了和FLask-Script有相同的功能,我们扩展了flasky.py模块。
import os
from app import create_app, db
from app.models import User, Follow, Role, Permission, Post, Comment
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
@app.shell_context_processor
def make_shell_context():
return dict(app=app, db=db, User=User, Follow=Follow, Role=Role,
Permission=Permission, Post=Post, Comment=Comment)
正如你看见的,作用时相同的,但是你需要@app.shell_context_processor
装饰器使Flask知道这些shell上下文对象
增加Flask拓展的命令
Flask-Script取得成功的一个很大关键在于允许Flask拓展添加他们自己的命令。Flask-Migrate库就最大限度利用了这一个优点。
所以如何迁移这些命令到flask-cli呢?这取决于拓展的作者是如何做迁移的,如果你使用的扩展正未曾为FLask Cli做出适配,那么你得继续使用FLask-Script,至少当你与这些拓展直接进行交互时得这样。Flask migrate提供了对于FLask Cli的更新,直接使用它最新的版本即可。
对于Flask Migrate, ./manage.py db
直接变成了 flask db
。在Flask-Script中我们Flask-Migrate在manage.py中被初始化,在FLaskCli中我们需要将Flask-Script版本中manage.py中的内容移入flasky.py中,只有一些微小的不同。
import os
from app import create_app, db
from app.models import User, Follow, Role, Permission, Post, Comment
from flask_migrate import Migrate
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(app=app, db=db, User=User, Follow=Follow, Role=Role,
Permission=Permission, Post=Post, Comment=Comment)
在示例中,我们使用接下来的命令更新flasky的数据库到最新的版本。(不要忘记设置FLASK_APP)
flask db upgrade
应用命令
Flask Script另一个优秀的特点是允许你把自己的常用任务(custom work)封装函数在命令行中执行。在CLI中你也只需要添加一个装饰器就能够完成迁移
原先的./manage.py test命令
@manager.command
def test(coverage=False):
"""Run the unit tests."""
# ...
在Flask-Cli中
import click
# ...
@app.cli.command()
@click.option('--coverage/--no-coverage', default=False, help='Enable code coverage')
def test(coverage):
"""Run the unit tests."""
# ...
@app.cli.command()装饰器提供了接口给Click。因为在Flask-Script中命令函执行是在应用上下文中的,而Flask-Cli中应用上下文如果你不需要是可以禁用的。在此处,函数的实际代码不需要改变,但注意coverage选项需要显式使用@click.option装饰器,而在flask-script中,该选项是自动导出的函数的参数列表。
Flasky其他两个函数也可以使用同样的方法,flasky模块的完全实现如下
import os
from app import create_app, db
from app.models import User, Follow, Role, Permission, Post, Comment
from flask_migrate import Migrate
import click
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(app=app, db=db, User=User, Follow=Follow, Role=Role,
Permission=Permission, Post=Post, Comment=Comment)
@app.cli.command()
@click.option('--coverage/--no-coverage', default=False, help='aaa')
def test(coverage=False):
"Test coverage"
# ...
@app.cli.command()
@click.option('--length', default=25, help='Profile stack length')
@click.option('--profile-dir', default=None, help='Profile directory')
def profile(length, profile_dir):
"""Start the application under the code profiler."""
# ...
@app.cli.command()
def deploy():
"""Run deployment tasks."""
# ...
总结
在本文中,我向您展示了新的CLI命令行所提供的功能,这有助于你从Flask-Script中迁移。还有两件事本文并没有提及,
如果你不想使用flask命令,如何创建类似于flask-script的manage.py的你自己的驱动脚本?
如何通过工程中”setup.py"中的’Entry points“注册命令?
你可以查阅[CLI Documention](CLI documenation )来了解他们
从Flask-Script迁移到Flask-Cli的更多相关文章
- 细说flask数据库迁移
什么情况下要用数据库迁移? 在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库.最直接的方式就是删除旧表,但这样会丢失数据. 更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化 ...
- 对于AttributeError: 'Flask' object has no attribute 'cli'的解决办法
版权声明:本文为博主原创文章,未经博主允许不得转载. 环境flask-script2.0.5.flask0.10.1 运行官方文档sample 出现问题 c:\kk\flask\examples\fl ...
- python 全栈开发,Day142(flask标准目录结构, flask使用SQLAlchemy,flask离线脚本,flask多app应用,flask-script,flask-migrate,pipreqs)
昨日内容回顾 1. 简述flask上下文管理 - threading.local - 偏函数 - 栈 2. 原生SQL和ORM有什么优缺点? 开发效率: ORM > 原生SQL 执行效率: 原生 ...
- day94:flask:Jinjia2模板引擎&flask中的CSRF攻击&Flask-SQLAlchemy的创建模型类和基本的增删改查
目录 1.Jinjia2模板引擎 1.Jinjia2加载模板并传递数据到模板中 2.Jinjia2的模板语句 3.模板中特有的变量和函数 4.模板中内置的过滤器 5.自定义过滤器 6.模板继承 2.在 ...
- Flask最强攻略 - 跟DragonFire学Flask - 第六篇 Flask 中内置的 Session
Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪 1. Flask 中 session 是需要 secret_key 的 from ...
- Flask最强攻略 - 跟DragonFire学Flask - 第四篇 Flask 中的模板语言 Jinja2 及 render_template 的深度用法
是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...
- 使用Flask+uwsgi+Nginx部署Flask正式环境
环境准备 在开始正式讲解之前,我们将首先进行环境准备. Step1:安装Python,pip以及nginx: sudo apt-get update sudo apt-get install pyth ...
- Flask 入门一( flask 框架和 flask-script 库)
Flask 入门一( flask 框架 和 flask-script 库) 一.Flask框架: 1.简介 Flask是一个非常小的Python Web框架,被称为微型框架:只提供了一个稳健的核心,其 ...
- 初识Flask框架,以及Flask中的模板语言jinjia2和Flask内置的Session
一.web框架的对比 首先我们先来看下比较火的web框架 1.Django: 优点:大而全,所有组件都是组织内部开发高度定制化,教科书级别的框架 缺点:大到浪费资源,请求的时候需要的资源较高 2.Fl ...
- Flask(3)- flask中的CBV、werkzeug+上下文初步解读、偏函数和线程安全
一.flask中的CBV 对比django中的CBV,我们来看一下flask中的CBV怎么实现? from flask import Flask, render_template, url_for, ...
随机推荐
- lmbench的使用方法
一.引言 要评价一个系统的性能,通常有不同的指标,相应的会有不同的测试方法和测试工具,一般来说为了确保测试结果的公平和权威性,会选用比较成熟的商业测试软件.但在特定情形下,只是想要简单比较不同系统或比 ...
- MySQL DDL Demo
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11606833.html DDL Demo CREATE TABLE `user` ( `id` ) u ...
- HDU 6053 TrickGCD —— 2017 Multi-University Training 2
TrickGCD Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- 10.15 sed 命令实践
在n行前插入 [root@wen data]# sed '2i 106,dandan,CSO' person.txt101,oldboy,CEO106,dandan,CSO102,zhangyao,C ...
- element table组件懒加载
directives : { loadmore : { bind(el, binding) { const selectWrap = el.querySelector('.el-table__body ...
- 怎么更改win7登录界面
方法/步骤 1 第一步,先打开注册表.快捷键是win+R.Win就是Windows图片那个键.打开会是这个. 2 在其中输入Regedit.就打开了传说中的注册表了.然后在注册表中选择.选择的顺序 ...
- NGINX配置之二: nginx location proxy_pass 后面的url 加与不加/的区别.
这里我们分4种情况讨论 这里我们请求的网站为:192.168.1.123:80/static/a.html 整个配置文件是 server{ port 80, server name 192.168.1 ...
- JS基础入门篇(四)—this的使用,模拟单选框,选项卡和复选框
1.this的使用 this js中的关键字 js内部已经定义好了,可以不声明 直接使用 this的指向问题 1. 在函数外部使用 this指向的是window 2. 在函数内部使用 有名函数 直接调 ...
- 前端每日实战:38# 视频演示如何用纯 CSS 创作阶梯文字特效
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/MXYBEM 可交互视频教程 此视频 ...
- 【原】webpack--plugins,主要解释plugins干了啥
其实呢,plugins是增强webpack的功能, 插件用于bundle文件的优化,资源管理和环境变量的注入, 可以理解为任何loaders不能做的事让它来做, 作用于整个构建过程. 常见的plugi ...