Python 如何以编程方式运行/调用flask cli命令?

Python 如何以编程方式运行/调用flask cli命令?,python,flask,database-migration,alembic,flask-migrate,Python,Flask,Database Migration,Alembic,Flask Migrate,我使用Python3和flask,以及flask migrate(使用alembic)来处理SQL迁移。当我运行本地集成测试时,我希望每次都重建数据库,这样我就可以针对我正在测试的每个API调用针对一个干净的db运行API调用(是的,我可以使用sqlite,但我希望检查约束是否正确) 我可以在命令行上轻松地执行以下操作: mysql -uroot -e 'drop database DBNAME; create database DBNAME;' FLASK_APP=flask_app.py f

我使用Python3和flask,以及flask migrate(使用alembic)来处理SQL迁移。当我运行本地集成测试时,我希望每次都重建数据库,这样我就可以针对我正在测试的每个API调用针对一个干净的db运行API调用(是的,我可以使用sqlite,但我希望检查约束是否正确)

我可以在命令行上轻松地执行以下操作:

mysql -uroot -e 'drop database DBNAME; create database DBNAME;'
FLASK_APP=flask_app.py flask db upgrade
但出于两个原因,我宁愿在python代码中运行它:

  • 我不想担心mysql客户端被安装在最终将运行此代码的CI机器上(它们应该只需要安装python mysql包)
  • 我想操纵flask设置以强制数据库名称以避免意外(因此它需要与调用它的脚本在相同的线程/内存空间中运行)
  • app
    对象(使用
    app=Flask(\uuuu name\uuuu)
    创建)有一个
    cli
    属性,但它需要一个上下文对象,并且感觉我没有使用正确的工具。我期望
    app.cli.invoke('db','upgrade')
    或类似的


    关于如何在不使用子cli进程的情况下从代码中调用flask命令,有什么建议吗?

    这不是很好,但最终我避免了直接使用flask命令,这似乎满足了我的需要:

    from my.app import app, db, initialize_app
    from flask_migrate import Migrate
    from alembic import command
    from my.settings import settings
    from sqlalchemy_utils.functions import drop_database, create_database, database_exists
    
    test_db_name = 'test_db'
    db_url = f'mysql+pymysql://mysqluser@127.0.0.1/{test_db_name}'
    settings.SQLALCHEMY_DATABASE_URI = db_url
    
    
    def reset():
        if database_exists(db_url):
            drop_database(db_url)
        create_database(db_url)
        initialize_app(app) # sets flask config SQLALCHEMY_DATABASE_URI to include test_db
        with app.app_context():
            config = Migrate(app, db).get_config()
            command.upgrade(config, 'head')
    

    我使用以下模式(见下文)。另一种方法可以在

    #文件:commands.py
    导入点击
    从中单击导入传递上下文
    从flask.cli导入AppGroup,使用_appcontext
    从flask导入当前应用程序
    从flask\u迁移导入迁移
    从alembic导入命令
    从extensions将flask_db导入为db
    db_cli=AppGroup('db',help='各种数据库管理命令!')
    @db_cli.命令('init')
    def db_init():
    “”“初始化数据库。”“”
    db.create_all()
    单击.echo(“创建所有表”)
    @db_cli.命令('drop')
    def db_drop():
    “”“删除数据库。”“”
    db.engine.execute(“设置外键检查=0;”)
    db.drop_all()
    db.engine.execute(“设置外键检查=1;”)
    单击.echo(“删除所有表”)
    @db_cli.命令('migrate')
    def db_migrate():
    “使用alembic进行迁移。”
    config=Migrate(当前的应用程序,db).get\u config()
    升级命令(配置'head')
    @db_cli.命令('db_upgrade')
    @传递上下文
    def db_升级(ctx):
    “”“数据库重置”的别名。”
    db_drop.invoke(ctx)
    db_init.invoke(ctx)
    db_migrate.invoke(ctx)
    
    #文件:extensions.py
    #将扩展分开,以允许在不使用导入循环的情况下导入。
    从flask_sqlalchemy导入sqlalchemy
    flask_db=SQLAlchemy()
    
    #文件:app.py(app/_init__;u.py),无论您的应用程序构建在何处
    从扩展导入
    app=烧瓶(名称)
    flask_db.init_app(app)#我不确定订单在这里是否重要。
    app.cli.add_命令(db_cli)
    
    #文件:wsgi.py(顶级文件)
    #此文件允许您运行“烧瓶”命令(例如烧瓶路径)
    #无检查未溶解参考
    从应用程序导入应用程序作为应用程序#noqa
    

    用法:
    flaskdb升级

    我认为这样的帖子可以帮助你。不过这有一个缺点。通常,您希望分配给应用程序的数据库用户没有完全的管理员权限,但只有足够的权限使用一个数据库。为应用程序使用管理员用户存在安全风险,如果有人获得了您的db管理员凭据,则可能会清除您的数据库服务器。标准做法是为仅对数据库具有读写访问权限的应用程序使用有限的用户。在这些情况下,您可以使用
    db.drop_all()
    删除数据库中的所有表,而无需删除数据库本身。
    # file layout
    - /
      - app/  (or app.py)
        - __init__.py  (optional)
      - commands.py
      - extensions.py
      - wsgi.py