Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask factory pattern and Flask CLI commands

Ok, i'm a bit new to Flask, so I'm not sure if i should be using Flask Script or Flask's built-in CLI took but I'm going with the latter for now.

However, I'm facing the problem that others have faced when it comes to bootstrapping the app context before running a command and having current_app context and whatnot.

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.cli.add_command(seed_db)
    return app

@click.command
@with_appcontext
def seed_db():
     # Register SqlAlchemy
    from .models import db, User, Role
    db.init_app(app)

    # Setup Flask-Security
    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security = Security(app, user_datastore)

    # Some initial models (if they don't exist)
    user_datastore.find_or_create_role(name='admin', description='Administrator')
    user_datastore.find_or_create_role(name='end-user', description='End user')

    return app

So in this case I have a factory method initializing the app. And then I have my custom command that I want to run to seed the database.

I've already been able to run flask db migrate to set up my initial tables, but if I try to run flask seed_db, I get something like this:

File "/usr/local/lib/python3.6/site-packages/click/core.py", line 1150, in add_command name = name or cmd.name AttributeError: 'function' object has no attribute 'name'

Can someone enlighten me on how to properly bootstrap the app with commands outside the create_app method?

like image 556
AlxVallejo Avatar asked Oct 23 '25 19:10

AlxVallejo


2 Answers

There is an error when you are using @click.command

I think the error message gives you a clear clue that you forget to give a name to your command.

You need to init a name to the command like this @click.command("seed_db") or just default function name like this @click.command()

@click.command("seed_db")
@with_appcontext
def seed_db():
  # Register SqlAlchemy
  from .models import db, User, Role
  db.init_app(app)

Hope it helps.

like image 135
nngeek Avatar answered Oct 26 '25 09:10

nngeek


These two lines are in the wrong place:

app.cli.add_command(seed_db)

return app

Your seed_db() function is adding itself to the app, which is a bit confusing - then returning the app. I think you meant for these two actions to occur your app factory method:

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.cli.add_command(seed_db)
    return app

Your app factory is the function with the responsibility of setting up the app object and returning it, no other function should be trying to do this.

like image 32
daveruinseverything Avatar answered Oct 26 '25 10:10

daveruinseverything