Flask Snippets

Lazy SQLAlchemy setup

By Dan Jacob filed in Database

If you are using the new Flask configuration together with the application factory pattern, one thing you will want to do if using SQLAlchemy is initialize a SQLAlchemy session for different requirements. For example, for unit tests you don't want to use the production database.

Furthermore you may need to use a SQLAlchemy session outside the request scope, for example in the shell.

The scoped_session function, which provides a thread-safe session, expects a factory function. Normally we would use sessionmaker:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

engine = create_engine("sqlite:///myapp.db")

db_session = scoped_session(sessionmaker(bind=engine))

In order to initialize SQLAlchemy dynamically however we need to pass in a factory function that does not require a ready engine instance. For this we can use create_session:

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, create_session

engine = None

db_session = scoped_session(lambda: create_session(bind=engine))

We then need a function to create the engine when needed:

def init_engine(uri, **kwargs):
    global engine
    engine = create_engine(uri, **kwargs)
    return engine

Provided you call init_engine first you can then use db_session thereafter, as the scoped_session will bind the session to the current value of engine.

You can call init_engine in your application factory function:

def create_app(config):
    
    app = Flask(__name__)
    app.config.from_pyfile(config)
    
    init_engine(app.config['DATABASE_URI'])
    
    return app

Now you can use the db_session anywhere in your application, as long as you first call create_app.

This snippet by Dan Jacob can be used freely for anything you like. Consider it public domain.

Comments