按视图更改数据库与每个视图访问多个数据库

4 投票
2 回答
1701 浏览
提问于 2025-04-16 23:32

我在使用SQLAlchemy和Pyramid时遇到了一些问题。虽然我能找到一些需要的例子,但通常都很简短,缺乏详细信息。所以我写出来的代码总是很零散,几乎没有什么意义。我希望能有人给我一个更完整的例子,告诉我该怎么做。

我有4个数据库,它们的结构是一样的。我想在一个Pyramid应用中操作这4个数据库,有时候需要列出所有数据库的“订单”,有时候只想列出“site1”的所有“订单”。因为它们的结构相同,所以我也用相同的模型类来处理这些数据库。

我尝试过使用sqlahelper和普通的SQLAlchemy,但都没有成功。下面的代码使用了sqlahelper,但我愿意尝试任何能工作的东西:

__init__.py

site1_eng = engine_from_config(settings, prefix='site1.')
site2_eng = engine_from_config(settings, prefix='site2.')
site3_eng = engine_from_config(settings, prefix='site3.')

sqlahelper.add_engine(site1_eng, 'site1_eng')
sqlahelper.add_engine(site2_eng, 'site2_eng')

views.py

def site_orders(request):
    site = request.matchdict['site']
    db_eng = sqlahelper.get_engine(("%s_eng" % (site)))
    conn = db_eng.connect()
    dbsession = sqlahelper.get_session()
    dbsession.configure(bind=conn)

    orders = dbsession.query(Order).order_by(Order.cdate.desc())[:100]

    return dict(orders=orders, pagetitle=(site+" Orders"))

发生了什么?

我本希望根据URL切换数据库,结果它确实可以!不过,它选择的数据库似乎完全是随机的。比如访问/orders/site1/时,有时会连接到site2的数据库,有时又是site3。每次刷新页面,选择的数据库也会变化。其他URL也是如此。

感觉就像是会话没有绑定到特定的数据库,而是随机选择了当前会话中存在的数据库?这可能说得不太清楚——我对SQLAlchemy的理解不是很好。

我真的希望有人能帮忙,因为这完全依赖于在视图中快速、轻松地切换数据库,而现在看起来完全无法控制。

注意: 我最开始尝试过跟着Pyramid SQLA+URL Dispatcher的教程,使用了:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))

但在找到sqlahelper后我把它去掉了。如果我应该使用它,请告诉我。

2 个回答

1

你可以直接把引擎设置到sqlalchemy会话中。

下面是一个示例,展示如何从四个数据库中列出所有的“订单”:

def site_orders(request):
    ...
    orders = []
    for engine in engines:
        dbsession.bind = engine
        orders += dbsession.query(Order).order_by(Order.cdate.desc())[:100]

    return dict(orders=orders, pagetitle=(site+" Orders"))
8

每次请求都要配置和连接,感觉工作量挺大的。我会在我的模型模块里创建四个会话处理器,然后直接从中选择一个使用。

举个例子:

models/__init__.py

DBSession1 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))  
DBSession2 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))  
DBSession3 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))  
DBSession4 = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))  
metadata1 = MetaData()                                                           
metadata2 = MetaData()                                                           
metadata3 = MetaData()                                                           
metadata4 = MetaData()                                                           

def initialize_sql(engines, drop_db=False):                                      
    DBSession1.configure(bind=engine[0])
    DBSession2.configure(bind=engine[1])                                            
    DBSession3.configure(bind=engine[2])                                            
    DBSession4.configure(bind=engine[3])                                            
    metadata1.bind = engine[0]                                            
    metadata2.bind = engine[1]                                            
    metadata3.bind = engine[2]                                            
    metadata4.bind = engine[3]  

然后在你的视图里:

from mypackage.models import DBSession1, DBSession2, DBSession3, DBSession4

def site_orders(request)                                                      
    site = request.matchdict['site']                                                      
    dbsession = globals().get("DBSession%d" % site)                                                      
    orders = dbsession.query(Order).order_by(Order.cdate.desc())[:100]                                                      
    return dict(orders=orders, pagetitle=(site+" Orders"))

撰写回答