flaskflask-migrateflask-script

using flask-migrate with flask-script and application factory


I'm building flask application and decided to try application factory approach this time, but got into trouble with flask-migrate and can't figure out simple solution.

Please note that I want to pass config location as an option to the script

manage.py:

manager = Manager(create_app)
manager.add_option("-c", "--config", dest="config_module", required=False)

then i need to create migrate instance and add command to the manager:

with manager.app.app_context():
    migrate = Migrate(current_app, db)
    manager.add_command('db', MigrateCommand)

but app instance is not created yet, so it fails

I know I can pass config in environment variable and create application before creating manager instance, but how to do it using manager options?


Solution

  • When you use a --config option you have to use an application factory function as you know, as this function gets the config as an argument and that allows you to create the app with the right configuration.

    Since you have an app factory, you have to use the deferred initialization for all your extensions. You instantiate your extensions without passing any arguments, and then in your app factory function after you create the application, you call init_app on all your extensions, passing the app and db now that you have them.

    The MigrateCommand is completely separate from this, you can add that to the Manager without having app and db instances created.

    Example:

    manage.py:

    from app import create_app
    from flask_migrate import MigrateCommand, Manager
    
    manager = Manager(create_app)
    manager.add_option("-c", "--config", dest="config_module", required=False)
    manager.add_command('db', MigrateCommand)
    

    app.py (or however your app factory module is called)

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate
    
    db = SQLAlchemy()
    migrate = Migrate()
    
    def create_app(config):
        app = Flask(__name__)
        # apply configuration
        # ...
    
        # initialize extensions
        db.init_app(app)
        migrate.init_app(app, db)
    
        return app