使用 SQLAlchemy、SQLite 和 Postgresql 架构限定表?

Posted

技术标签:

【中文标题】使用 SQLAlchemy、SQLite 和 Postgresql 架构限定表?【英文标题】:Schema qualified tables with SQLAlchemy, SQLite and Postgresql? 【发布时间】:2011-02-10 18:28:13 【问题描述】:

我有一个 Pylons 项目和一个实现模式限定表的 SQLAlchemy 模型:

class Hockey(Base):
    __tablename__ = "hockey"
    __table_args__ = 'schema':'winter'
    hockey_id = sa.Column(sa.types.Integer, sa.Sequence('score_id_seq', optional=True), primary_key=True)
    baseball_id = sa.Column(sa.types.Integer, sa.ForeignKey('summer.baseball.baseball_id'))

此代码在 Postgresql 上运行良好,但在表和外键名称上使用 SQLite 时失败(由于 SQLite 缺乏架构支持)

sqlalchemy.exc.OperationalError: (OperationalError) 未知数据库 "winter" 'PRAGMA "winter".table_info("hockey")' ()

我想继续使用 SQLite 进行开发和测试。

有没有办法在 SQLite 上优雅地失败?

【问题讨论】:

在您的开发和测试机器上使用 Postgres 有什么困难? 我会让您的设置更简单。从头到尾使用 Postgres。不要在 SQLIte 上测试并在 Postgres 上发布。 坚持使用 SQLite 可以简化工作流程,特别是对于 QA 人员,因为他们不必了解自己的测试数据库。随处使用 Postgres 是一个可靠的计划“B” 您是否尝试过使用engine.execute("attach database 'db' as winter;".format(db=_SL_FILE)) 来解决这个问题?顺便说一句,我同意 StarShip3000 关于 PostgreSQL 的评论。 @Chris:要将新创建的内存数据库附加到现有(内存或文件)数据库,只需运行engine.execute("attach database ':memory:' as db_name;")。我不知道如何附加已经存在的内存数据库(将现有的基于文件的数据库附加到内存数据库没有问题)。所以你基本上必须改变创建顺序:首先附加内存数据库(创建一个新数据库),然后为这个新的内存数据库创建表并根据需要填充数据。 【参考方案1】:

我想继续使用 SQLite 开发和测试。

有没有办法让这个失败 优雅地使用 SQLite?

很难知道从哪里开始提出这类问题。所以 。 . .

停下来。停下来吧。

有些开发人员没有在他们的目标平台上开发的奢侈。他们的生活是艰难的——将代码(有时是编译器)从一个环境移动到另一个环境,调试两次(有时必须在目标平台上远程调试),逐渐意识到他们内心的痛苦实际上是溃疡的开始。

安装 PostgreSQL。

当您可以使用相同的数据库环境进行开发、测试和部署时,您应该

更不用说 QA 团队了。他们到底为什么要测试他们不会发货的东西?如果您在 PostgreSQL 上进行部署,请确保您在 PostgreSQL 上的工作质量。

说真的。

【讨论】:

我的编辑是一个新的答案。这个答案有我的全文。另一个是我对 QA 中所有优秀人员的明显关注。 如果每个人都可以访问以进行开发和测试的服务器可用,则可以将PostgreSQL安装在该服务器上,而不是本地安装在所有机器上。这将减轻测试人员的负担,因为他们不需要安装它。【参考方案2】:

我自己也只是个初学者,也没用过 Pylons,但是……

我注意到您正在将表和关联的类组合在一起。如果把它们分开呢?

import sqlalchemy as sa
meta = sa.MetaData('sqlite:///tutorial.sqlite')
schema = None
hockey_table = sa.Table('hockey', meta,
                      sa.Column('score_id', sa.types.Integer, sa.Sequence('score_id_seq', optional=True), primary_key=True),
                      sa.Column('baseball_id', sa.types.Integer, sa.ForeignKey('summer.baseball.baseball_id')),
                      schema = schema,
                    )

meta.create_all()

然后你可以创建一个单独的

class Hockey(Object):
    ...

mapper(Hockey, hockey_table)

如果您使用 sqlite,则只需在上面设置 schema = None,否则设置您想要的值。

您没有有效的示例,因此上面的示例也不是有效的示例。然而,正如其他人所指出的,试图保持跨数据库的可移植性最终是一场失败的游戏。我会为那些建议你在任何地方都使用 PostgreSQL 的人加一个 +1。

HTH,问候。

【讨论】:

那些有合作政策的人在Linux端进行应用开发时使用MSSQL(Windows产品)怎么办?虽然考虑到当前数据的数据量,使用 PostgreSQL 真的很酷,但迁移还遥遥无期。【参考方案3】:

我不确定这是否适用于外键,但有人可以尝试使用 SQLAlchemy 的 Multi-Tenancy Schema Translation for Table objects。它对我有用,但我将自定义 primaryjoinsecondaryjoinexpressions 与复合主键结合使用。

架构翻译映射可以直接传递给引擎创建者:

...

if dialect == "sqlite":
    url = lambda: "sqlite:///:memory:"
    execution_options="schema_translate_map": "winter": None, "summer": None
else:
    url = lambda: f"postgresql://user:pass@host:port/name"
    execution_options=None

engine = create_engine(url(), execution_options=execution_options)

...

这是create_engine 的文档。还有一个question,在这方面可能与此有关。

但是可能会出现冲突的表名,所有模式名都映射到None

【讨论】:

【参考方案4】:

我知道这是一个 10 多年前的问题,但我最近遇到了同样的问题:生产中的 Postgres 和开发中的 sqlite。

解决方案是在引擎调用“connect”方法时注册一个事件监听器。

@sqlalchemy.event.listens_for(engine, "connect")
def connect(dbapi_connection, connection_record):
    dbapi_connection.execute('ATTACH "your_data_base_name.db" AS "schema_name"')

只使用一次 ATTACH 语句是行不通的,因为它只影响一个连接。这就是为什么我们需要事件监听器,在所有连接上创建 ATTACH 语句。

【讨论】:

以上是关于使用 SQLAlchemy、SQLite 和 Postgresql 架构限定表?的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 查询引发关于 sqlite 和 Decimal 的不必要警告,如何专门禁用?

Scrapy - SQLite 中未创建 SQLalchemy 外键

SQLAlchemy:pool_size 和 SQLite

使用Flask SQLAlchemy从SQLite切换到MySQL

SQLAlchemy 选择在 SQLite 表上给出不同的结果,原始 sql 与可选

使用 Flask 中的 SQLAlchemy 会话会引发“在线程中创建的 SQLite 对象只能在同一线程中使用”