用多个数据库提供页面

0 投票
3 回答
3145 浏览
提问于 2025-04-17 19:55

我现在有:多个一模一样的数据库和一个SQL-Alchemy的设置。

我想要实现的目标是:有一个“Flask”函数能够查询所有的数据库。其他的函数只需要访问其中一个数据库。

这些数据库已经存在,我正在从中加载数据。

最开始我只是使用SQL-Alchemy的抽象层,没有使用任何Flask模型。代码大概是这样的:

app = Flask(__name__)
app.config.from_object('myflaskapp.config.settings')
metadata = None

def connect_db():
    engine = create_engine(app.config['DATABASE_URI'])
    global metadata
    metadata = MetaData(bind=engine)
    return engine.connect()

@app.before_request
    def before_request():
    g.db = connect_db()

@app.after_request
    def after_request(response):
    close_connection()
    return response

其中DATABASE_URI是在settings.py中定义的。我想这没什么关系,不过底层的数据库是一个Mysql服务器,DATABASE_URI看起来像这样:

DATABASE_URI = 'mysql://' + dbuser + ':' + dbpass + '@' + dbhost + '/' +dbname

上面的代码让我可以写出类似这样的代码:

myTable = Table('branch', metadata, autoload=True)
myBranch = select([myTable])

这非常方便。这个方法运行得很好,前提是我只处理一个数据库。不过,如果我需要处理多个数据库,就不太行了。更准确地说,我想在同一个函数中显示属于多个数据库的数据,而这些数据库的结构完全相同。也就是说,针对任何一个数据库都可以成功运行相同的查询。用伪代码表示大概是这样的:

@app.route('/summary')
def summary():
     ....
     allData = []
     for db in all_of_my_dbs:
         allData.append(db.query())
     ....
sendToTemplate(allData) 

这能实现吗?可行吗?谢谢。

3 个回答

0

看起来这个问题上有个小bug - https://github.com/mitsuhiko/flask-sqlalchemy/pull/222。问题在于,绑定的键必须是唯一的,并且只能用于一个类(至少目前是这样)。所以你可以有多个数据库,但每个数据库只能有一个表或一个类。不过,如果你有很多表的话,这样做会消耗很多资源,暂时这只是个权宜之计……

这里是关于“绑定”的参考资料 - http://flask-sqlalchemy.pocoo.org/2.0/binds/#binds

下面是配置的内容:

SQLALCHEMY_DATABASE_URI = 'sqlite://///main.db'

SQLALCHEMY_BINDS= {

'table1':'sqlite://///DB1.db',

'table2':'sqlite://///DB2.db',

}

下面是模型的定义:

class table1(db.Model):

__tablename__ = "table1"
__bind_key__='table1'

class table2(db.Model):

__tablename__ = "table2"
__bind_key__='table2'
0

首先,我想说说我自己的情况。这里有两个表,它们的名字和结构是一样的,但它们属于不同的数据库或模式。

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

app = Flask(__name__)

databases = {
    'sqlite1': 'sqlite:///sqlite1.db',
    'sqlite2': 'sqlite:///sqlite2.db'
}

app.config['SQLALCHEMY_BINDS'] = databases
db = SQLAlchemy(app)

class Thing(db.Model):
    __tablename__ = "mytable"
    __bind_key__ = 'sqlite1'
    thing_id = db.Column(db.Integer, primary_key=True)
    thing_val = db.Column(db.String(40))

    def __init__(self, thing_val):
        self.thing_val = thing_val


if __name__ == "__main__":

    t1 = Thing.query.filter_by(thing_id=1).first()
    print t1.name

当我在第一个类定义后面添加第二个类,叫做Thing2的时候,一切就崩溃了。也就是说:

class Thing(db.Model):
    __tablename__ = "mytable"
    __bind_key__ = 'sqlite1'
    thing_id = db.Column(db.Integer, primary_key=True)
    thing_val = db.Column(db.String(40))

    def __init__(self, thing_val):
        self.thing_val = thing_val


class Thing2(db.Model):
    __tablename__ = "mytable"
    __bind_key__ = 'sqlite2'
    thing_id = db.Column(db.Integer, primary_key=True)
    thing_val = db.Column(db.String(40))

    def __init__(self, thing_val):
        self.thing_val = thing_val

上面的代码出错了,错误信息是:

InvalidRequestError: 表 'mytable' 已经在这个MetaData实例中定义过了。请指定 'extend_existing=True' 来重新定义现有表对象的选项和列。

所以这个框架似乎无法区分这两个表。

0

这绝对是可能的

试着在你的设置文件里添加类似下面的内容

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

编辑

这里有一个可以直接复制粘贴的示例

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

app = Flask(__name__)
app.debug = True

databases = {
    'sqlite1': 'sqlite:///sqlite1.db',
    'sqlite2': 'sqlite:///sqlite2.db'
}
app.config['SQLALCHEMY_BINDS'] = databases
db = SQLAlchemy(app)

class Thing(db.Model):
    __tablename__ = "sqlite1"
    thing_id = db.Column(db.Integer, primary_key=True)
    thing_val = db.Column(db.String(40))

    def __init__(self, thing_val):
        self.thing_val = thing_val

class Thing2(db.Model):
    __tablename__ = "sqlite2"
    thing_id = db.Column(db.Integer, primary_key=True)
    thing_val = db.Column(db.String(40))

    def __init__(self, thing_val):
        self.thing_val = thing_val


if __name__ == "__main__":

    db.create_all()
    t1 = Thing("test1")
    t2 = Thing2("test2")

    db.session.add(t1)
    db.session.add(t2)
    db.session.commit()

    t1 = Thing.query.filter_by(thing_id=1).first()
    t2 = Thing2.query.filter_by(thing_id=1).first()

    print t1.thing_val
    print t2.thing_val

撰写回答