I'd like to use Flask-Migrate and am looking at their example:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
if __name__ == '__main__':
manager.run()
This works great as a simple play example, but I have more than a single model and I don't want to define the models in both this script and the one that defines my application code. Thus, I want to pull them into a model file that I can share between the two.
I attempting to do this, by placing the User
class into a models.py
and then importing User from there. Unfortunately, that throws a NameError: name 'db' is not defined
.
My question(s) are:
- Do I need to use
db = SQLAlchemy(app)
in my models.py
, and if so will this be available in both my migration script and the flask application itself?
- If I can't (or shouldn't) put it in
models.py
, how do I utilize my models in their own file without passing db
all over?
Partitioning such a small application into modules is tricky, because you find a lot of cases where the two modules that you create need to mutually import each other, creating circular dependencies.
I recommend that you look at how you can structure a larger application properly, using an app factory function and delayed initialization of all extensions. An example application that does this is the Flasky app featured in my book.
All that said, it is possible to separate the application into two parts, you just need to be careful with where you place the import statements. In the example below, I decided to move the creation of the db
instance and the User
model into a models.py file.
Here is the main application's module:
from flask import Flask
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
from models import db # <-- this needs to be placed after app is created
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
And here is models.py:
from __main__ import app
from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
Here the main module will create app
, and only then will import models.py. When models.py tries to import app
from the main module, it has already been created. If you move from models import db
to the top of the file with the other imports this code breaks.
Here is an idea. You can create a package model
in which you define classes as individual .py
files. For example, user.py
contains the User
class.
In the __init__.py
file you can define the db
variable. You may also include from user import User
statement so that it would be possible to access User
object directly outside the package. For example you can import the model
package somewhere else in the program using import model
and then use model.User
to directly use the User
class.
To use db
variable directly in the user.py
use from ..model import db
which imports db
variable defined in the __init__.py
file.