SQLAlchemy与多个数据库

30 投票
2 回答
19405 浏览
提问于 2025-04-17 18:17

我有一些相似但不完全相同的数据库,想用SQLAlchemy来“统一”访问这些数据库。这些数据库可能在细节上有些不同,比如列名有独特的前缀,或者更明显的差异,比如缺少某些列(或者对于旧数据库,缺少整个表)。

我需要帮助的其实不是SQLAlchemy的问题,而是关于Python和组织结构的问题。我该如何设置多个数据库,以便在项目中可以轻松重用呢?

我读过关于SQLAlchemy会话的内容,但我找不到不需要在每个项目中都实例化它们的方法。

我的问题是:我该如何制作一个模块或包,里面包含多个数据库模型设置,可以在SQLAlchemy中使用,并且能在其他Python项目中轻松导入和使用?

目前我不太担心缺少列或表的问题。我可以稍后再处理这个问题,但我需要记住这一点,因为我不能对每个数据库使用完全相同的模型。

如果有任何相关的资源、建议或阅读材料,我将非常感激。提前谢谢你,如果这个问题在别处已经回答过,我很抱歉,搜索时没有找到相关内容。

编辑:我保留了原文,并根据保罗的建议添加了更多内容。

关于SA ORM - 是的,我打算使用SQLAlchemy的ORM。出于显而易见的原因,我不能提供真实的数据库。不过,假设有这三个虚构的数据库,分别叫DB1、DB2和DB3(我们假设每个数据库里有一张表,只有几列,现实中会有更多的列和表)。

每个数据库都有一个用户表,每个表里有几列。以下是一些关于表和列的SQL表示法:

DB1.user  --> DB1.user.id,      DB1.user.username,  DB1.user.email
DB2.user  --> DB2.user.id,      DB2.user.user_name, DB2.user.email
DB3._user --> DB3._user.userid, DB3._user.username, DB3.user.email_address

目前,我正在尝试将这些数据库分离成“模块化”,并能够随着时间的推移轻松添加额外的数据库。

我考虑了几种不同的文件组织方式(假设需要的地方有__init__.py,但为了简洁省略了),包括:

Databases         |    Databases            |    Databases
    DB1.py        |        DB1              |        DB1
    DB2.py        |            models.py    |            models
    DB3.py        |        DB2              |                user.py
                  |            models.py    |                anothertable.py
                  |        DB2              |        ...
                  |            models.py    |        DB3
                  |                         |            models
                  |                         |                user.py
                  |                         |                anothertable.py

我希望能通过SA ORM访问这些数据库,并在使用这些数据库时尽量减少导入和声明的数量。需要做类似于:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from Database import DB1, ..., DB[N]
db1_engine = create_engine('connect_string/db1')
db1_session = sessionmaker(bind=db1_engine)()
...
db3_engine = create_engine('connect_string/db3')
db3_session = sessionmaker(bind=db3_engine)()

这样的事情会非常麻烦,因为我将处理的数据库远不止三个。我更希望这些事情能在我使用时就已经处理好(也许在__init__.py文件中?)

能够像这样访问和使用它:

import Databases

Databases.DB1.session.query('blahblah')

会好得多。

编辑2:我也知道在设置模型时如何处理数据库/列命名约定的差异。这不是问题,但我提到这一点是为了说明我不能对多个数据库使用同一套模型。

我希望通过扩展这个内容没有让事情变得更加复杂或困惑。感谢你花时间阅读!

编辑3:我已经花了一些时间在这个问题上。我按照以下方式设置了项目:

Databases
    __init__.py
    databases.py
    settings.py
    DB1
        __init__.py
        models.py
    ...
    DB3
        __init__.py
        models.py

目前,我在settings.py文件中有一个数据库的元组,像这样“安装”了它们。每个条目看起来像INSTALLED_DATABASES = ('DB1', ..., 'DB3')。随着我完成更多模型,它们会被添加到这个元组列表中。这让我可以随时添加或删除内容。

我在models.py文件中设置了引擎和会话,并且为每个数据库的init.py文件设置了from models import *

在databases.py文件中,我有以下内容:

class Databases(object):
    def __init__(self):
        for database in INSTALLED_DATABASES:
            setattr(self, database, __import__(database))

我现在可以通过:

from databases import Databases

db = Databases()

for qr in db.DB1.query(db.DB1.User):
    print qr.userid, qr.username

来使用这些。SQLAlchemy让我在定义模型时手动指定列名,这对我想要的标准化来说是个很大的好处。

我还有很多工作要做。我希望创建一些对象来强制模型验证(例如,某个字段是否存在?不存在的字段是否有默认值?等等),并更好地将其与我的IDE结合起来(目前这方面做得不太好)。但我已经走上了正确的道路。我想更新这个内容,以便那些可能想知道如何做同样事情的人参考。

抱歉这段内容变得这么长!

谢谢!

2 个回答

3

你的解决方案看起来不错。让我来分享一下我做的事情。

我有一个叫做 connectors 的包,里面有每个数据库对应的模块,还有一个设置文件。

每个连接器模块都会创建它自己的连接字符串和引擎,同时还会定义基础类和表的类。

接着有一个叫 loadSession 的方法,它会返回一个会话(这个方法我是在某个教程或者其他帖子里看到的,具体记不清了),我还添加了另一个方法,可以返回引擎,以便我想用的时候能方便操作。

所以在程序的其他模块里,我会这样做:

from connectors import x, y, z

x_ses = x.loadSession()
y_ses = y.loadSession()
z_ses = z.loadSession()

xq = x_ses.query(...)
yq = y_ses.query(...)
8

根据大家对我最初问题的反馈,我把我的第三次修改作为了答案。因为我不太确定正确的流程,所以我把第三次修改保留在上面。如果你已经看过EDIT3,那你就看到了我的答案。

我花了一些时间在这个项目上。我把项目设置成了以下的方式:

Databases
    __init__.py
    databases.py
    settings.py
    DB1
        __init__.py
        models.py
    ...
    DB3
        __init__.py
        models.py

目前,我在settings.py文件中有一个数据库的元组,这些数据库是“已安装”的。每个数据库的条目在INSTALLED_DATABASES = ('DB1', ..., 'DB3')中指定。随着我完成更多的模型,它们会被添加到这个元组列表中。这让我可以在进行过程中随时添加或删除内容。

我在models.py文件中设置了引擎和会话,并且每个数据库的__init.py__文件都设置为from models import *

在databases.py文件中,我有以下内容:

class Databases(object):
    def __init__(self):
        for database in INSTALLED_DATABASES:
            setattr(self, database, __import__(database))

现在我可以通过以下方式使用这些:

from databases import Databases

db = Databases()

for qr in db.DB1.query(db.DB1.User):
    print qr.userid, qr.username

SQLAlchemy让我在定义模型时手动指定列名,这对我想要的标准化来说是个很大的好处。

我还有很多工作要做。我想创建一些对象来强制模型验证(比如,一个字段是否存在?一个不存在的字段是否有默认值?等等),并且更好地将这个过程与我的IDE结合起来(目前这方面做得不太好)。但我已经走上了正确的道路。我觉得有必要更新一下这个内容,以便那些可能想知道如何做同样事情的人。

抱歉这段内容变得这么长!

谢谢!

撰写回答