我想在单个 sqlalchemy 数据库模型中使用多个数据库引擎。

以下情况:
我有一个相册软件(python),不同的相册存储在不同的文件夹中。在每个文件夹中都有一个单独的 sqlite 数据库,其中包含有关照片的附加信息。我不想使用单个全局数据库,因为通过这种方式,我可以简单地移动、删除和复制基于文件夹的相册。
打开单个专辑相当简单:

创建数据库 session :

maker = sessionmaker(autoflush=True, autocommit=False,
                 extension=ZopeTransactionExtension())
DBSession = scoped_session(maker)

db 模型的基类和元数据:
DeclarativeBase = declarative_base()
metadata = DeclarativeBase.metadata

定义数据库模型(缩短):
pic_tag_table = Table('pic_tag', metadata,
                      Column('pic_id', Integer,
                             ForeignKey('pic.pic_id'),
                             primary_key=True),
                      Column('tag_id', Integer,
                             ForeignKey('tag.tag_id'),
                             primary_key=True))


class Picture(DeclarativeBase):
    __tablename__ = 'pic'

    pic_id = Column (Integer, autoincrement = True, primary_key=True)
    ...


class Tags(DeckarativeBase):
    __tablename__ = 'tag'

    tag_id = Column (Integer, autoincrement = True, primary_key=True)
    ...

    pictures = relation('Picture', secondary=pic_tag_table, backref='tags')

最后打开连接:
engine = engine_from_config(config, '...')
DBSession.configure(bind=engine)
metadata.bind = engine

这适用于打开一张专辑。现在我想同时打开多个专辑(和数据库连接)。每张专辑都有相同的数据库模型,所以我希望我可以重用它。我的问题是模型类定义是从连接到元数据和数据库引擎的声明性基础继承而来的。我想使用不同的引擎将类连接到不同的元数据。这可能吗?

P.S.:我也想通过 ORM 查询数据库,例如DBSession.query(Picture).all()(或 DBSession[0], ... 用于不同数据库上的多个 session - 所以不是对所有数据库中的所有图片进行一次查询,而是一种用于查询一个数据库的 ORM 样式查询)

最佳答案

您可以使用多个引擎和 session 来实现这一点(您不需要多个元数据):

engine1 = create_engine("sqlite:///tmp1.db")
engine2 = create_engine("sqlite:///tmp2.db")
Base.metadata.create_all(bind=engine1)
Base.metadata.create_all(bind=engine2)
session1 = Session(bind=engine1)
session2 = Session(bind=engine2)
print(session1.query(Picture).all())  # []
print(session2.query(Picture).all())  # []
session1.add(Picture())
session1.commit()
print(session1.query(Picture).all())  # [Picture]
print(session2.query(Picture).all())  # []
session2.add(Picture())
session2.commit()
print(session1.query(Picture).all())  # [Picture]
print(session2.query(Picture).all())  # [Picture]
session1.close()
session2.close()

对于 scoped_session ,您也可以创建多个。
engine1 = create_engine("sqlite:///tmp1.db")
engine2 = create_engine("sqlite:///tmp2.db")
Base.metadata.create_all(bind=engine1)
Base.metadata.create_all(bind=engine2)
Session1 = scoped_session(sessionmaker(bind=engine1))
Session2 = scoped_session(sessionmaker(bind=engine2))
session1 = Session1()
session2 = Session2()
...

如果您需要打开的数据库数量可变,那么 scoped_session 可能有点麻烦。你需要一些方法来跟踪它们。

10-06 15:47
查看更多