dimanche 24 décembre 2017

Create one SQLAlchemy instance per blueprint and call create_all multiple times

My application has a blueprint which is intended to be modular and uses its own database models. I use an app-factory pattern.

Two problems that I face often with such a project structure are:

  • Cyclical imports.
  • The inability to pass around the db object to the blueprints in a clean manner such that they can create their own database models.

To avoid passing the db object around I have now started to create a new database object (db = SQLAlchemy()) within the blueprints itself.

It works! And also avoids some issues with cyclical imports as well since the blueprint now uses its own instance of db. My questions is, what kind of problems will this design lead to? I use gunicorn with a gevent worker.

Here's some sample code to show how my models and factory are structured:

blueprints.status.models.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class Status(db.Model):
    __tablename__ = 'states'
    id = db.Column(db.Integer, primary_key=True)
    job_id = db.Column(db.Integer)
    status = db.Column(db.String(120))

models.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class Job(db.Model):
    __tablename__ = 'states'
    id = db.Column(db.Integer, primary_key=True)
    state = db.Column(db.String(120)

factory.py

from .blueprints.status.models import db as status_db  # blueprint db
from .blueprints.status.routes import status_handler   # blueprint handler
from .models import db as root_db                      # root db
from flask import Flask

def create_app():
    app = Flask(__name__)

    # Create database resources.
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////path/to/app.db'
    root_db.init_app(app)
    status_db.init_app(app)
    with app.app_context():
        root_db.create_all()
        status_db.create_all()  # <--- What problems will this lead to?

    # Register blueprint routes.
    app.register_blueprint(status_handler, url_prefix="/status")

    return app

Aucun commentaire:

Enregistrer un commentaire