AlxVallejo
AlxVallejo

Reputation: 3238

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?

Upvotes: 4

Views: 2916

Answers (2)

nngeek
nngeek

Reputation: 1377

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.

Upvotes: 5

daveruinseverything
daveruinseverything

Reputation: 5187

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.

Upvotes: 1

Related Questions