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的更多相关文章

  1. 细说flask数据库迁移

    什么情况下要用数据库迁移? 在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库.最直接的方式就是删除旧表,但这样会丢失数据. 更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化 ...

  2. 对于AttributeError: 'Flask' object has no attribute 'cli'的解决办法

    版权声明:本文为博主原创文章,未经博主允许不得转载. 环境flask-script2.0.5.flask0.10.1 运行官方文档sample 出现问题 c:\kk\flask\examples\fl ...

  3. python 全栈开发,Day142(flask标准目录结构, flask使用SQLAlchemy,flask离线脚本,flask多app应用,flask-script,flask-migrate,pipreqs)

    昨日内容回顾 1. 简述flask上下文管理 - threading.local - 偏函数 - 栈 2. 原生SQL和ORM有什么优缺点? 开发效率: ORM > 原生SQL 执行效率: 原生 ...

  4. day94:flask:Jinjia2模板引擎&flask中的CSRF攻击&Flask-SQLAlchemy的创建模型类和基本的增删改查

    目录 1.Jinjia2模板引擎 1.Jinjia2加载模板并传递数据到模板中 2.Jinjia2的模板语句 3.模板中特有的变量和函数 4.模板中内置的过滤器 5.自定义过滤器 6.模板继承 2.在 ...

  5. Flask最强攻略 - 跟DragonFire学Flask - 第六篇 Flask 中内置的 Session

    Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪 1. Flask 中 session 是需要 secret_key 的 from ...

  6. Flask最强攻略 - 跟DragonFire学Flask - 第四篇 Flask 中的模板语言 Jinja2 及 render_template 的深度用法

    是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...

  7. 使用Flask+uwsgi+Nginx部署Flask正式环境

    环境准备 在开始正式讲解之前,我们将首先进行环境准备. Step1:安装Python,pip以及nginx: sudo apt-get update sudo apt-get install pyth ...

  8. Flask 入门一( flask 框架和 flask-script 库)

    Flask 入门一( flask 框架 和 flask-script 库) 一.Flask框架: 1.简介 Flask是一个非常小的Python Web框架,被称为微型框架:只提供了一个稳健的核心,其 ...

  9. 初识Flask框架,以及Flask中的模板语言jinjia2和Flask内置的Session

    一.web框架的对比 首先我们先来看下比较火的web框架 1.Django: 优点:大而全,所有组件都是组织内部开发高度定制化,教科书级别的框架 缺点:大到浪费资源,请求的时候需要的资源较高 2.Fl ...

  10. Flask(3)- flask中的CBV、werkzeug+上下文初步解读、偏函数和线程安全

    一.flask中的CBV 对比django中的CBV,我们来看一下flask中的CBV怎么实现? from flask import Flask, render_template, url_for, ...

随机推荐

  1. 【串线篇】sql映射文件-分布查询(下)cellection的1-n

    1.场景 一个门人手一把钥匙 1-n 一个Lock对应一个Key集合(collection自动整成list) Map不是collection的子接口或者实现类.Map是一个接口. JavaBean:p ...

  2. Halo(九)

    跨域问题 域名A(http://www.a.com)的 Web 应用程序中, 通过标签引入了域名B(http://ww.b.com)站点的某图片资源(http://www.b.com/image.jp ...

  3. [原创] Delphi 修改新建窗体时候的默认字体格式

    Delphi 修改新建窗体时候的默认字体格式 操作步骤: 1.运行输入“regedit” 2.找到目录(这里默认以Delphi 7为例) HKEY_CURRENT_USER\Software\Borl ...

  4. 学习笔记:Apache Kylin 概述

    一.kylin解决了什么关键问题? Apache Kylin的初衷就是解决千亿.万亿条记录的秒级查询问题,其中的关键就是打破查询时间随着数据量呈线性增长的这一规律. 大数据OLAP,我们可以注意到两个 ...

  5. 报错——userdel: user hhh is currently used by process 9218

    报错 userdel: user hhh is currently used by process 9218 [root@centos71 ~]# useradd hhh [root@centos71 ...

  6. Android中插件开发篇总结和概述

    刚刚终于写完了插件开发的最后一篇文章,下面就来总结一下,关于Android中插件篇从去年的11月份就开始规划了,主要从三个方面去解读Android中插件开发原理.说白了,插件开发的原理就是:动态加载技 ...

  7. Distribution money

    Distribution money Accepts: 713 Submissions: 1881 Time Limit: 2000/1000 MS (Java/Others) Memory Limi ...

  8. vue数据渲染、条件判断及列表循环

    1.数据渲染  {{msg}} <template> <div id="app"> {{msg}} </div> </template&g ...

  9. nginx 虚拟主机+反向代理+负载均衡

    nginx是一款免费.开源的http服务器,它是由俄罗斯程序设计师开发的,官方测试,nginx能支撑5万的并发量,主要功能有虚拟主机.反向代理和负载均衡等. nginx配置 # 全局块 ... # e ...

  10. Linux环境下对大小写敏感,linux环境升级node

    linux对大小写敏感 在window下可以正常运行的代码,在linux环境下报错,找不到文件,因为window下对大小写不敏感,linux对大小写敏感 linux环境下node升级 1.安装nvm ...