Flask and SQLAlchemy without the Flask-SQLAlchemy Extension
When using SQLAlchemy with Flask, the standard approach is to use the Flask-SQLAlchemy extension.
However, this extension has some issues. In particular, we have to use a base class for our SQLAlchemy models that creates a dependency on flask (via flask_sqlalchemy.SQLAlchemy.db.Model
). Also, an application may not require the additional functionality that the extension provides, such as pagination support.
Let’s see if we can find a way to use plain SQLAlchemy in our Flask applications without relying on this extension.
This article focuses specifically on connecting a Flask application to SQLAlchemy directly, without using any plugins or extensions. It doesn’t address how to get a Flask application working on its own, or how SQLAlchemy works. It may be a good idea to get these parts working separately first.
Below is the code that sets up the SQLAlchemy session (db.py):
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
engine = create_engine(os.environ['SQLALCHEMY_URL'])
Session = scoped_session(sessionmaker(bind=engine))
The key here is scoped_session
: Now when we use Session
, SQLAlchemy will check to see if a thread-local session exists. If it already exists, then it will use it, otherwise it will create one first.
The following code bootstraps the Flask application (__init__.py):
from flask import Flask
from .db import Session
from .hello import hello_blueprint
app = Flask(__name__)
app.register_blueprint(hello_blueprint)
@app.teardown_appcontext
def cleanup(resp_or_exc):
Session.remove()
The @app.teardown_appcontext
decorator will cause the supplied callback, cleanup
, to be executed when the current application context is torn down. This happens after each request. That way we make sure to release the resources used by a session after each request.
In our Flask application, we can now use Session
to interact with our database. For example (hello.py):
import json
from flask import Blueprint
from .db import Session
from .models import Message
hello_blueprint = Blueprint('hello', __name__)
@hello_blueprint.route('/messages')
def messages():
values = Session.query(Message).all()
results = [{ 'message': value.message } for value in values]
return (json.dumps(results), 200, { 'content_type': 'application/json' })
This should be sufficient for integrating SQLAlchemy into a Flask application.
For a more detailed overview of the features Flask-SQLAlchemy provides, see Derrick Gilland’s article, Demystifying Flask-SQLAlchemy
We also get the benefit of not having to create a dependency on Flask for our SQLAlchemy models. Below we’re just using the standard sqlalchemy.ext.declarative.declarative_base
(models.py):
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class Message(Base):
__tablename__ = 'messages'
id = Column(Integer, primary_key=True)
message = Column(String)
def __repr__(self):
return "<Message(message='%s')>" % (self.message)
I could be wrong, but I would prefer to start a project with this approach initially, and only to incorporate the Flask-SQLAlchemy extension later if it turns out to be demonstrably useful.
This code is available on github: https://github.com/nestedsoftware/flask_sqlalchemy_starter