5

I am confused about how to use Flask-Migrate when I have multiple models. Basically my Flask app looks like this:

app
├── __init__.py
├── config.py
├── manage.py
├── migrations
├── models
│   ├── model1.py
│   ├── model2.py
├── resources
├── run.py
└── tests

I've read that for each model its best to create the db = SQLAlchemy() object in the file and then import this db object into the app's__init__.py like so:

from models.model1 import db
db.init_app(app)
from models.model2 import db
db.init_app(app)

However if I do this for multiple model files, how can I add Flasks's migrate functionality, considering I can only use 1 sql alchemy object for the migrate class instantiation:

migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)

Would it be best in this case to define a single sql alchemy object in the __init__.py file and import that into all my models?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
a_corn
  • 75
  • 2
  • 6

1 Answers1

11

You misread the referenced text. That talks about something completely different. That talks about keeping your db object separate from the app object (and tie the two togther in the create_app factory function). Creating multiple db objects is only complicating matters for you.

All that is needed is a single db = SQLAlchemy() object, and all the files that define models need to be imported. Usually that's done directly or indirectly via your create_app factory function, You need to call the create_app() function anyway to be able to run the flask db command-line tool anyway.

Next, you do not need to create a manager either. The Manager object is a hold-over from the time before the Flask project added support for scripts itself. If you are using Flask 0.12 or newer, you don't want to be using Flask-Script and it's manager.

So, all you need, in your __init_.py, is:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate


db = SQLAlchemy()


def create_app(test_config=None):
    app = Flask(__name__)

    app.config.from_object(f"{__name__}.config")
    app.config.from_envvar("PROJECTNAME_SETTINGS", silent=True)
    if test_config:
        app.config.from_mapping(test_config)

    db.init_app(app)
    Migrate(app, db)

    # importing the models to make sure they are known to Flask-Migrate
    from models import models1, models2

    # any other registrations; blueprints, template utilities, commands

    return app
tirenweb
  • 30,963
  • 73
  • 183
  • 303
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    The problem here is that you cannot describe your model without db: ``` class User(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128)) ``` Should i init `db` inside models package and suck it into create_app? Or i should create `db` near create_app and pass it down to models package and initialize every model dynamically somehow? – a0s May 07 '22 at 13:07
  • @a0s you can create the db instance anywhere you like and import it where it is needed; I keep mine in the module with the `create_app()` factory because other Flask extensions may refer to it too, but it doesn’t really matter. – Martijn Pieters May 07 '22 at 13:43