Configure Flask-SQLAlchemy
- Set metadata above
- Start writing!
- Create
start
folder - Create
end
folder - Create per-file diff between
end
andstart
(use "Compare Folders")
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)
@app.before_first_request
def create_tables():
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. - Registered a function to run before our Flask app handles its first request. The function will tell SQLAlchemy to use what it knows in order to create all the database tables we need.
How does SQLAlchemy know what tables to create?
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.