【问题标题】:Where should I implement flask custom commands (cli)我应该在哪里实现烧瓶自定义命令(cli)
【发布时间】:2019-12-03 18:39:21
【问题描述】:

在flask中创建自定义命令需要访问app,一般在app.py中创建如下:

import click
from flask import Flask

app = Flask(__name__)

@app.cli.command("create-user")
@click.argument("name")
def create_user(name):
    ...

但是,为了不使我的 app.py 膨胀,我想将我的自定义命令放在一个单独的文件中,例如commands.py,但这不起作用,因为我的项目的入口点是 app.py,所以我必须在 commands.py 中导入应用程序并在 app.py 中导入我的命令,这会导致循环导入错误。

如何在单独的文件中创建自定义命令?

【问题讨论】:

  • 我不确定,但你可能需要with app.app_context():,检查this
  • @Roman 是的,但我需要先导入应用程序才能执行with app.app_context():。所以同样的问题仍然存在。
  • 您还可以检查一个较旧的类似问题stackoverflow.com/a/54824126/606826 的响应,简而言之,创建一个工厂函数并将您的应用程序作为参数传递def register_cli(app: Flask):

标签: python flask command-line-interface python-click flask-cli


【解决方案1】:

实现此目的的一种方法是使用blueprints

我已经使用 Flask 1.1.1 对其进行了测试,因此请务必检查您拥有的正确版本的文档。

大致思路如下:

  1. 在不同的文件中创建一个或多个蓝图,假设它名为 commands.py
  2. 然后导入新的蓝图并将它们注册到您的应用中

==> app.py

from flask import Flask
from commands import usersbp

app = Flask(__name__)
# you MUST register the blueprint
app.register_blueprint(usersbp)

==> commands.py

import click
from flask import Blueprint

usersbp = Blueprint('users', __name__)

@usersbp.cli.command('create')
@click.argument('name')
def create(name):
    """ Creates a user """
    print("Create user: {}".format(name))

在执行flask users 时,您应该得到如下响应:

flask users
Usage: flask users [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  create  Creates a user

【讨论】:

  • 是的,它被记录为注册自定义命令:flask.palletsprojects.com/en/1.1.x/cli/…。但是,有没有办法在不使用蓝图的情况下注册自定义命令?
  • 这是最好的可行方案
  • 请注意,蓝图默认添加命令组,如果这不是您想要的,请检查文档中的cli_group 选项。
【解决方案2】:

只需将其导入您的应用工厂

dir tree

my_app
     L app.py
     L commands.py

commands.py

@app.cli.command('resetdb')
def resetdb_command():
    """Here info that will be shown in flask --help"""
    pass

app.py

def create_app():
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db.init_app(app)

    with app.app_context():
        from . import routes
        from . import commands  # <----- here

        return app
$ export FLASK_APP=my_app/app.py
$ flask resetdb

但必须有更好的方法;)我现在不知道

【讨论】:

  • 这是“通过谷歌搜索找到的所有烧瓶 cli 解决方案,包括烧瓶 cli 文档本身”中唯一对我有用的解决方案
  • 如何将app 导入commands.py 中?
【解决方案3】:

如果您不使用应用工厂模式,什么对我有用,类似于@quester:

app.py

import os

from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
migrate = Migrate(app, db)

with app.app_context():
    # needed to make CLI commands work
    from commands import *

commands.py

from app import app

@app.cli.command()
def do_something():
    print('hello i am so nice I posted this even though I have 100 other things to do')

【讨论】:

  • 这有效吗?我遇到循环依赖问题。 ImportError: cannot import name 'app' from partially initialized module 'app' (most likely due to a circular import)
【解决方案4】:

如果您使用的是应用工厂(您有 create_app() 函数),那么您甚至没有要导入的 app 变量。

保持代码井井有条的最佳方法是在其他地方定义函数,然后在构建应用程序实例时注册它。

例如

my_app/
 | main.py
 | app/
 |  | __init__.py
 |  | commands.py

commands.py

def foo():
   print("Running foo()")

init.py

def create_app():
 app = Flask(__name__)
 ...
 from .commands import foo
 @app.cli.command('foo')
 def foo_command():
   foo()
 ...

【讨论】:

    【解决方案5】:

    我有这个布局:

    baseapp.py

    from flask import Flask
    
    app = Flask("CmdAttempt")
    

    app.py

    from .baseapp import app
    
    def main():
        app.run(
            port=5522,
            load_dotenv=True,
            debug=True
        )
    
    if __name__ == '__main__':
        main()
    

    commands.py

    import click
    
    from .baseapp import app
    
    
    @app.cli.command("create-super-user")
    @click.argument("name")
    def create_super_user(name):
        print("Now creating user", name)
    
    
    if __name__ == '__main__':
        from .app import main
        main()
    

    在您运行命令的控制台中,首先将FLASK_APP 定义为commands.py,然后运行您定义的命令。

    set FLASK_APP=commands.py
    export FLASK_APP=commands.py
    flask create-super-user me
    

    您可以为内置命令使用单独的终端,也可以在发出它们之前清除FLASK_APP 变量。在 Linux 中更容易,因为您可以这样做

    FLASK_APP=commands.py flask create-super-user me
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-07
      • 2015-10-28
      • 2016-03-11
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多