從Flask-Script遷移到Flask-Cli

Abstrct

flask從0.11版本開始引入了click提供命令行支持,在此以前咱們一般會引入Flask-Script來提供。python

在《Flask web開發》這本書編寫時flask0.11尚未發佈,所以書中仍然以flask-script提供命令行支持。所以在flask0.11發佈一年後,做者寫了這篇文章來幫助你們從flask-script遷移到Flask-Cli,該博文即是做者這篇文章的翻譯。git

做者對於Click引入flask的意見

回到2014年,當Armin Ronacher向我介紹將Click整合進flask,我是(如今也是)拒絕的,這給Flask內核項目添加了別的依賴,我建議基於click實現命令行支持做爲flask的拓展,與flask-script進行公平的競爭。你能夠查看該討論在GitHub的issue中 https://github.com/smurfix/flask-script/issues/97github

所以我確信,強制命令行工具基於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-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時,你盡能夠移除它。

使用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來了解他們

相關文章
相關標籤/搜索