flask从0.11版本开始引入了click提供命令行支持,在此以前咱们一般会引入Flask-Script来提供。python
在《Flask web开发》这本书编写时flask0.11尚未发布,所以书中仍然以flask-script提供命令行支持。所以在flask0.11发布一年后,做者写了这篇文章来帮助你们从flask-script迁移到Flask-Cli,该博文即是做者这篇文章的翻译。git
回到2014年,当Armin Ronacher向我介绍将Click整合进flask,我是(如今也是)拒绝的,这给Flask内核项目添加了别的依赖,我建议基于click实现命令行支持做为flask的拓展,与flask-script进行公平的竞争。你能够查看该讨论在GitHub的issue中 https://github.com/smurfix/flask-script/issues/97。github
所以我确信,强制命令行工具基于Click是个错误,而且违反了flask的基本准则‘将最优秀的工具用于每一项任务’ 。并且不幸的是,click成为flask核心的一部分使flask-script的维护者离开了,并且从github的repository来看,这个项目彷佛正在缓慢死亡web
那么,flask-script有什么问题呢?shell
flask确实有着一个重要可是同时却足够有趣的缺陷,因为早期设计的flask reloader的问题,你将直接使用app.run()启动你的应用而不是Flask-Script数据库
若是你以debug模式启动flask,那么将有两个flask进程被运行。第一个进程(咱们能够称他为watcher)将会观察源代码的运行,第二个进程才是实际的flask服务器。当任何文件被修改时,这个watcher一旦观察到文件改变将会kill服务进程,而后启动一个使用已经更新的源代码的服务器进程。当你更新的某个源文件中存在语法错误时,会出现一个问题。Watcher进程并不知道源码是否更好,它会kill旧的服务器进程,运行一个新的服务器进程。可是新的服务器进程却不会运行成功,由于python解析修改后的文件时会抛出错误。当服务进程存在在错误时,这个watcher进程也会退出,直到你修复了bug并重启。flask
在你使用新的命令flask run命令行时load将会很完美,直到你第一个request发来以前,应用都不会被加载,当引入源码文件有错误时,他将会被在运行时处理,这意味着你可使用基于web的debug工具。新的watcher进程也更加智能,在服务端被kill后仍然会坚持监控源码的变化,并在源码发生改变以后重启服务。服务器
Flask-Cli比Flask-Script更加优秀吗?让咱们回顾下新的Flask应用提供的默认命令吧app
当你安装Flask0.11或者更新的版本后,你的环境变量将会存在flask命令ide
(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时,你尽能够移除它。
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-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来了解他们