Use Flask's Click CLI with the app factory pattern

前端 未结 2 1612
南旧
南旧 2020-12-30 09:44

I define my Flask application using the app factory pattern. When using Flask-Script, I can pass the factory function to the Manager. I\'d like to use Flask\'s

相关标签:
2条回答
  • 2020-12-30 09:58

    The flask command is a Click interface created with flask.cli.FlaskGroup. Create your own group and pass it the factory function. Use app.shell_context_processor to add objects to the shell.

    from flask import Flask
    from flask.cli import FlaskGroup
    from flask_sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    def create_app(script_info=None):
        app = Flask(__name__)
        db.init_app(app)
        ...
    
        @app.shell_context_processor
        def shell_context():
            return {'app': app, 'db': db}
    
        return app
    
    cli = FlaskGroup(create_app=create_app)
    
    @cli.command
    def custom_command():
        pass
    
    if __name__ == '__main__':
        cli()
    

    Run your file instead of the flask command. You'll get the Click interface using your factory.

    FLASK_DEBUG=1 python app.py run
    

    Ideally, create an entry point and install your package in your env. Then you can call the script as a command. Create a setup.py file with at least the following.

    project/
        app/
            __init__.py
        setup.py
    
    from setuptools import setup, find_packages
    
    setup(
        name='my_app',
        version='1.0.0',
        packages=find_packages(),
        entry_points={
            'console_scripts': [
                'app=app:cli',
            ],
        },
    )
    
    pip install -e /path/to/project
    FLASK_DEBUG=1 app run
    

    Using your own CLI is less robust than the built-in flask command. Because your cli object is defined with your other code, a module-level error will cause the reloader to fail because it can no longer import the object. The flask command is separate from your project, so it's not affected by errors in your module.

    0 讨论(0)
  • 2020-12-30 10:02

    In order to pass arguments to your app factory, you need to make use of script_info like so...

    manage.py

    #!/usr/bin/env python
    
    import click
    import config
    
    from flask import Flask
    from flask.cli import FlaskGroup, pass_script_info
    
    
    def create_app(script_info):
        app = Flask(__name__)
    
        if script_info.config_mode:
            obj = getattr(config, script_info.config_mode)
            flask_config.from_object(obj)
    
        ...    
        return app
    
    
    @click.group(cls=FlaskGroup, create_app=create_app)
    @click.option('-m', '--config-mode', default="Development")
    @pass_script_info
    def manager(script_info, config_mode):
        script_info.config_mode = config_mode
    
    
    if __name__ == "__main__":
        manager()
    

    config.py

    class Config(object):
        TESTING = False
    
    class Production(Config):
        DATABASE_URI = 'mysql://user@localhost/foo'
    
    class Development(Config):
        DATABASE_URI = 'sqlite:///app.db'
    
    class Testing(Config):
        TESTING = True
        DATABASE_URI = 'sqlite:///:memory:'
    

    now in the command line you can do manage -m Production run (after either adding the entry_points to setup.py as @davidism mentioned, or running pip install manage.py).

    0 讨论(0)
提交回复
热议问题