1、问题背景
在一个 Flask-SQLAlchemy 项目中,用户想要使用显式主主数据库设置。具体而言,他想要能够从默认数据库中读取数据,并将数据持久化到两个主数据库中。他希望知道是否可以使用 Flask-SQLAlchemy 和 binds 来实现这一目标。
2、解决方案
为了实现显式主主数据库设置,可以按照以下步骤进行操作:
- 定义 SQLAlchemy 应用程序配置
python
app = Flask(__name__)
# 定义默认数据库 URI
SQLALCHEMY_DATABASE_URI = 'default_DB_uri'
# 定义主数据库 URI
SQLALCHEMY_BINDS = { 'master1':'first_master_DB_uri', 'master2': 'second_master_DB_uri' }
# 将 SQLAlchemy 配置应用到 Flask 应用中
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_BINDS'] = SQLALCHEMY_BINDS
# 创建 SQLAlchemy 对象
db = SQLAlchemy(app)
- 自定义 Flask-SQLAlchemy 会话类
python
from flask_sqlalchemy import SQLAlchemy, SignallingSession, get_state
from flask_sqlalchemy._compat import itervalues
class UsingBindSignallingSession(SignallingSession):
def get_bind(self, mapper=None, clause=None):
if self._name:
_eng = get_state(self.app).db.get_engine(self.app,bind=self._name)
return _eng
else:
return super(UsingBindSignallingSession, self).get_bind(mapper, clause)
_name = None
def using_bind(self, name):
self._name = name
return self
class UsingBindSQLAlchemy(SQLAlchemy):
def create_session(self, options):
return UsingBindSignallingSession(self, **options)
def get_binds(self, app=None):
retval = super(UsingBindSQLAlchemy, self).get_binds(app)
# get the binds for None again in order to make sure that it is the default bind for tables
# without an explicit bind
bind = None
engine = self.get_engine(app, bind)
tables = self.get_tables_for_bind(bind)
retval.update(dict((table, engine) for table in tables))
return retval
def get_tables_for_bind(self, bind=None):
"""Returns a list of all tables relevant for a bind.
Tables without an explicit __bind_key__ will be bound to all binds.
"""
result = []
for table in itervalues(self.Model.metadata.tables):
# if we don't have an explicit __bind_key__ bind this table to all databases
if table.info.get('bind_key') == bind or table.info.get('bind_key') == None:
result.append(table)
return result
db = UsingBindSQLAlchemy()
- 使用自定义的 Flask-SQLAlchemy 会话类
python
# 创建一个默认数据库会话
session = db.session
# 创建一个主数据库会话
master_session1 = db.session().using_bind('master1')
# 创建另一个主数据库会话
master_session2 = db.session().using_bind('master2')
# 在默认数据库中读取数据
read_data = session.query('select ...').all()
# 在第一个主数据库中持久化数据
master_session1.add(SOME_OBJECT)
master_session1.commit()
# 在第二个主数据库中持久化数据
master_session2.add(SOME_OBJECT_CLONE)
master_session2.commit()
通过上述步骤,就可以实现显式主主数据库设置,并在 Flask-SQLAlchemy 中使用它。