Configure Flask-SQLAlchemy
We want to add two imports to app.py
:
from db import db
import models
The Flask app factory pattern
Up until now, we've been creating the app
variable (which is the Flask app) directly in app.py
.
With the app factory pattern, we write a function that returns app
. That way we can pass configuration values to the function, so that we configure the app before getting it back.
This is especially useful for testing, but also if you want to do things like have staging and production apps.
To do the app factory, all we do is place all the app-creation code inside a function which must be called create_app()
.
from flask import Flask
from flask_smorest import Api
from db import db
import models
from resources.item import blp as ItemBlueprint
from resources.store import blp as StoreBlueprint
def create_app():
app = Flask(__name__)
app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config[
"OPENAPI_SWAGGER_UI_URL"
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
api = Api(app)
api.register_blueprint(ItemBlueprint)
api.register_blueprint(StoreBlueprint)
return app
Add Flask-SQLAlchemy code to the app factory
from flask import Flask
from flask_smorest import Api
from db import db
import models
from resources.item import blp as ItemBlueprint
from resources.store import blp as StoreBlueprint
def create_app(db_url=None):
app = Flask(__name__)
app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config[
"OPENAPI_SWAGGER_UI_URL"
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
app.config["SQLALCHEMY_DATABASE_URI"] = db_url or os.getenv("DATABASE_URL", "sqlite:///data.db")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
api = Api(app)
with app.app_context():
db.create_all()
api.register_blueprint(ItemBlueprint)
api.register_blueprint(StoreBlueprint)
return app
We've done three things:
- Added the
db_url
parameter. This lets us create an app with a certain database URL, or alternatively try to fetch the database URL from the environment variables. The default value will be a local SQLite file, if we don't pass a value ourselves and it isn't in the environment. - Added two SQLAlchemy values to
app.config
. One is the database URL (or URI), the other is a configuration option which improves performance. - When the app is created, tell SQLAlchemy to create all the database tables we need.
The line import models
lets SQLAlchemy know what models exist in our application. Because they are db.Model
instances, SQLAlchemy will look at their __tablename__
and defined db.Column
attributes to create the tables.