Sqlalchemy 如何实现一表多库?

在多区域情况下,每个区域都要一套完整的数据体系。然而管控层一般都是统一的,需要经常按照区域识别查询数据库。Sqlalchemy 提供了多库绑定功能,参考实现如下:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData

# 多个数据库连接配置信息
SQLALCHEMY_BINDS = {
    'zbs': 'mysql://sharp:sharp@172.17.0.1:3306/zbs',
    'sharp': 'mysql://sharp:sharp@172.17.0.1:3306/sharp',
}

app = Flask(__name__)
app.config['SQLALCHEMY_BINDS'] = SQLALCHEMY_BINDS
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 由于使用了 Flask,这里就直接一起搞了
db = SQLAlchemy(app)


class ZbsVolume(db.Model):
    # 指定要连接的数据库
    __bind_key__ = 'zbs'
    # 指定对应的表名,默认是类名,这莫办法的事
    __tablename__ = 'volume'
    # 不然会爆表名冲突,无法初始化
    metadata = MetaData()

    id = db.Column(db.String(36), primary_key=True)
    volume_type_name = db.Column(db.String(255))


class SharpVolume(db.Model):
    __bind_key__ = 'sharp'
    __tablename__ = 'volume'
    metadata = MetaData()

    id = db.Column(db.String(36), primary_key=True)
    volume_type_name = db.Column(db.String(255))

定义好ORM,那使用就简单了,参考如下:

# 初始化数据库连接
db.create_all()
ZbsVolume.query.filter_by(id='fake').first()
# 新增一个
query = ZbsVolume(id=line, volume_type_name='hdd.std2)
db.session.add(query)

只有1个表两个库,这么写写也直观,如果要查 N 个表,又有 M 个库,这真成了无感情的机器人了。

动态生成 Model

这时候是不是想起来了类也是可以创建的,一个简单的元类不就行了,那我们就试试看

定义一个 meta.py 文件,用来存在原始表信息

from sqlalchemy import MetaData, Column, String, Integer

VolumeMeta = {
	'__tablename__': 'volume',
	'__table_args__': {'extend_existing': True},
	'metadata': MetaData(),
	'id': Column(String(36), primary_key=True),
	'volume_type_name': Column(String(255)),
}

定义 model.py,用来创建 model

class ModelFactor(object):

    def __init__(self):
        self.cache = {}
        self.regions = config.ZBS_MYSQL_MAP.keys()
        self.meta_dict = {
            'Volume': VolumeMeta,
            'fake1": FakeMeta,
        }

    @classmethod
    def make_model_key(cls, region, model):
        return '%s_%s' % (region, model)

    def create_model(self, region, model):
        if model not in self.meta_dict:
        logger.error("model <%s> not define" % model)
            return None
        if region not in self.regions:
            logger.error("region <%s> not define" % region)
            return None

        db = init_db()
        meta = self.meta_dict[model]
        meta['__bind_key__'] = region
        logger.info("Now create model <%s_%s>" % (region, model))
        return type(model, (db.Model,), meta)

    def select_model(self, region, model):
        key = self.make_model_key(region, model)
        if key not in self.cache:
            model = self.create_model(region, model)
            if model:
                self.cache[key] = model
        else:
            model = self.cache[key]
        return model

使用

model_factor = ModelFactor()
model = model_factor.select_model(region, 'Volume')
# 开始 orm 操作
posted @ 2021-10-17 22:53  last_coding  阅读(423)  评论(0编辑  收藏  举报