Где я должен реализовать колбу пользовательских команд (cli)
Создание пользовательских команд в колбе требует доступа к приложению, которое обычно создается в 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
что приводит к циклической ошибке импорта.
Как я могу создавать собственные команды в отдельных файлах?
7 ответов
Один из способов добиться этого - использовать чертежи.
Я тестировал его с помощью Flask 1.1.1, поэтому не забудьте проверить документацию на правильную версию, которая у вас есть.
Вот общая идея:
- Создайте один или несколько Blueprints в другом файле, скажем, он называется commands.py
- Затем импортируйте новые чертежи и зарегистрируйте их в своем приложении.
==> 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
Просто импортируйте его в свою фабрику приложений
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
но должен быть способ получше;) о котором я сейчас не знаю
Если вы используете фабрику приложений (у вас есть
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()
...
Моя практика:
├── app.py
├── команды.py
в app.py:
from commands import register_commands
def create_app():
app = Flask(__name__)
....
register_commands(app)
return app
в командах.py
from sqlalchemyseeder import ResolvingSeeder
from app import db
def register_commands(app):
@app.cli.command("seed_courses")
def seed_courses():
seeder = ResolvingSeeder(db.session)
seeder.load_entities_from_json_file("app/db/seed/data.json")
db.session.commit()
db.session.close()
@app.cli.command("command2")
def another_command():
print("another command")
бегать:
flask seed_courses
flask command2
Что сработало для меня, если вы не используете шаблон фабрики приложений, похожий на @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')
У меня такой расклад:
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
Мое решение:
приложение.py:
from flask import Flask
def create_app():
import commands
application = Flask(__name__)
application.cli.add_command(commands.hello)
return application
if __name__ == '__main__':
app = create_app()
app.run()
команды.py:
import click
@click.command("say_hello")
@click.argument("name")
def hello(name):
""" Say hello to user """
print(f"Hello {name}")