SQLAlchemy与多个数据库
我有一些相似但不完全相同的数据库,想用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 个回答
你的解决方案看起来不错。让我来分享一下我做的事情。
我有一个叫做 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(...)
根据大家对我最初问题的反馈,我把我的第三次修改作为了答案。因为我不太确定正确的流程,所以我把第三次修改保留在上面。如果你已经看过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结合起来(目前这方面做得不太好)。但我已经走上了正确的道路。我觉得有必要更新一下这个内容,以便那些可能想知道如何做同样事情的人。
抱歉这段内容变得这么长!
谢谢!