首页 文章

在多租户应用程序中动态设置Flask-SQLAlchemy数据库连接

提问于
浏览
15

我有一个“ multi-tenantFlask Web应用程序,它连接有1个"master" MySQL数据库(用于查找客户端信息)和数十个"client" MySQL数据库(它们都具有相同的模式) .

我目前正在尝试使用 SQLAlchemyFlask-SQLAlchemy extension 来连接数据库,但是我很难找到一种方法来允许我在我的应用中定义的模型 dynamically switch context from one client database to another ,具体取决于客户端 .

Flask-SQLAlchemy site上,一个简单的例子如下:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@Y.Y.Y.Y/db1'
db = SQLAlchemy(app)

class User(db.Model):
    # Etc.

唯一的问题是, SQLALCHEMY_DATABASE_URI 配置是静态完成的 . 我可能需要在 mysql://username:password@Y.Y.Y.Y/db1mysql://username:password@Z.Z.Z.Z/db1 (或任何其他任意MySQL URI)之间切换,具体取决于发出请求的客户端 .

我发现了一些类似的问题(见下文),但是在使用Flask-SQLAlchemy扩展时,我还没有找到一种干净的方法 .

With sqlalchemy how to dynamically bind to database engine on a per-request basis

Flask SQLAlchemy setup dynamic URI

我还看到了一些为处理分片数据库而提供的示例(也应该适用,因为数据库本质上是由客户端逻辑分片),但同样,Flask-SQLAlchemy没有特定的内容 .

如果有意义的话, I'm also open to using SQLAlchemy directly, without the Flask-SQLAlchemy extension . 我是SQLAlchemy的新手 - 非常感谢任何帮助!

Edit :能够从数据库中反映表模式将是一个奖励 .

2 回答

  • 0

    如果您使用的是flask-sqlalchemy 0.12或更高版本,则BINDS支持此功能 .

    SQLALCHEMY_DATABASE_URI = 'postgres://localhost/main'
    SQLALCHEMY_BINDS = {
    'users':        'mysqldb://localhost/users',
    'appmeta':      'sqlite:////path/to/appmeta.db'
    }
    

    您可以在模型定义中指定连接数据库 .

    class User(db.Model):
        __bind_key__ = 'users'
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True)
    

    它将使用mysqldb auto . 有关详细信息,请参阅官方文档 . Multiple Databases with Binds

  • 2

    你可以这样做 . 仅供参考,这是纯粹的SQLAlchemy,而不是Flask-SQLAlchemy . 希望你需要这个只读的东西 . 您可以找出其他一些东西来编写内容,比如甚至是会话/模型上的监听器

    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy.ext.declarative import declarative_base
    
    # an Engine, which the Session will use for connection
    # resources
    some_engine_1 = create_engine('postgresql://scott:tiger@localhost/')
    some_engine_2 = create_engine('postgresql://adriel:velazquez@localhost/')
    
    # create a configured "Session" class
    Session_1 = sessionmaker(bind=some_engine_1)
    Session_2 = sessionmaker(bind=some_engine_2)
    
    # create a Session
    session_1 = Session_1()
    session_2 = Session_2()
    
    Base = declarative_base()
    
    class ModelBase(Base):
        #different custom queries for each database
        master_query = session_1.query_property()
        client_1_query = session_2.query_property()
    
    
    class User(ModelBase):
        pass
        #ETC
    
    
    ##Accessing the different databases:
    User.master_query.filter(User.id == 1).all()
    User.client_1_query.filter(User.id == 1).all()
    

相关问题