使用 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。它对我有用,但我将自定义 primaryjoin
和 secondaryjoin
expressions 与复合主键结合使用。
架构翻译映射可以直接传递给引擎创建者:
...
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 外键
使用Flask SQLAlchemy从SQLite切换到MySQL