Share Flask-SQLAlchemy between two Flask apps
Asked Answered
E

1

8

I have two Flask apps running with a domain dispatcher (based on this guide).

I'd like to share my models between the apps. Is it safe to have the SQLAlchemy object in a shared location and just call db.init_app with both applications?

This is my project structure:

app_one/
├ __init__.py
├ database/
│ ├ __init__.py
│ └ models.py
└ ...
app_two/
├ __init__.py
├ database/
│ ├ __init__.py
│ └ models.py
└ ...
shared/
└ ...
dispatcher.py

This is dispatcher.py:

from flask import Flask
import app_one
import app_two


class Dispatcher:
    def __init__(self, config_file, app_one_config_file, app_two_config_file):
        self.app_one = app_one.create_app(config_file, app_one_config_file)
        self.app_two = app_two.create_app(config_file, app_two_config_file)

    def __call__(self, environ, start_response):
        host = environ['HTTP_HOST']
        if host == 'app_two_domain.com':
            return self.app_two(environ, start_response)
        return self.app_one(environ, start_response)


def create_app(*args, **kwargs):
    app = Flask(__name__)
    app.wsgi_app = Dispatcher(*args, **kwargs)
    return app

Currently both app_one/database/__init__.py and app_two/database/__init__.py contain:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy

And in both create_app functions:

from .database import db
db.init_app(app)

I'd like to move db into shared/database/__init__.py, and then either:

  • call init_app with both apps, or

  • make Dispatcher a subclass of Flask, call init_app in Dispatcher, and then register the Flask-SQLAlchemy extension with both apps with app.extensions['sqlalchemy'] = _SQLAlchemyState(db).

What's the right way to go about this? (Splitting app_one and app_two isn't an option.)

(Note: this is not a duplicate of this question, since both of my apps are Flask apps.)

Elect answered 7/6, 2020 at 2:39 Comment(0)
P
0

This is not a complete answer, feel free to edit this or add a new one.

Since you are using dispatcher anyway , create a 3rd app to solely handle the shared database and models. With that your file structure should look like

shared_db_app/
├ __init__.py
└ database/
  ├ __init__.py
  └ models.py

app_one/
├ __init__.py
├ database/
│ ├ __init__.py
│ └ models.py
└ ...
app_two/
├ __init__.py
├ database/
│ ├ __init__.py
│ └ models.py
└ ...
dispatcher.py

Initialization part
Your shared app shared/database/__init__.py should look something like:

from flask import Flask
from sqlalchemy import SQLAlchemy
from sqlalchemy.orm import scoped_session, sessionmaker

db = SQLAlchemy()

def init_db(app):
    db.init_app(app)

    @app.teardown_appcontext
    def remove_session(*args, **kwargs):
        db.session.remove()

    app.db_session = scoped_session(sessionmaker(autocommit=False,autoflush=False,bind=db.engine))

def get_session():
    return Flask(__name__).db_session

And each app calling this as:

from flask import Flask
from shared.database import init_db, get_session

app #whatever init you have to do
init_db(app)
app.db_session = get_session()

Models part
Now your models should all be in the shared shared_db_app/database/models.py as:

from shared_db_app.database import db

class User(db.Model):#eg

with the models in app 1 and 2 importing it (assuming you have seperate data or models to be handled in each app as well) as:

from shared_db_app.database.models import User

These two links might be of interest(Unfortunately both do not contain code or any more details):
Handling migrations in such a case
Answer on the same topic, this says no session handling is required since sql queues requests automatically.

Politian answered 7/5 at 0:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.