1

在配置 SQLAlchemy 模型时,有人可以帮助我了解全局,从而确保所有级别的引用完整性吗?

按照参照完整性应该由数据库表达和执行的想法,我创建了一个包含我认为需要的所有约束的模式(目前在 Postgresql 中),因此给我一个我信任的数据库将强制执行参照完整性。

然后我开始在这个数据库之上构建一个应用程序,在声明模式下使用 SQLAlchemy (0.7)。

经过一番搜索和阅读,我了解到我可以配置:

  • 我的 Column() 定义上的 onupdate/ondelete 规则。
  • 我的 relationship() 定义上的级联选项,
    并且这些似乎在 SQLAlchemy 的会话级别上运行。
  • 我的 relationship() 定义的passive_deletes 和passive_updates 选项。

并且所有这些选项都有默认值。

但是我对我实际上需要对我的 SQLAlchemy 模型做多少感到困惑,以确保 SQLAlchemy 在会话期间不会与数据库及其约束不同步。

如果我在 SQLAlchemy 中的 Columns() 定义上配置“onupdate”等,我到底要实现什么?

对于级联和passive_delete/passive_update 规则,我可以在relationship() 上进行配置。我在这里需要什么,为什么?

或者改写我的问题:SQLAlchemy 会在多大程度上了解数据库模式中配置的约束,以及我必须在多大程度上(以及如何)在我的模型中重复它们?

还有什么我应该注意的吗?:)

4

2 回答 2

4

SQLAlchemy 从根本上不需要了解您的数据库所具有的约束。如果您的数据库具有您想要配置的约束,那么您基本上已经完成 - 数据库不允许您的应用程序执行任何不应该执行的操作。

SQLAlchemy 的一个关键主题是它实际上只做你告诉它的事情。因此,如果您尝试在 SQLAlchemy 刷新数据(即发出 INSERT 语句)时持久化一个对象 SubWidget(),该对象在数据库中需要对父 Widget() 的引用,操作将失败约束冲突,由数据库发出,事务被回滚。

因此,假设“subwidget”上的 FK 引用“widget”,您的应用程序需要确保数据的结构正确。有两种方法可以做到这一点; 一种是您手动维护那些包含外键引用的列,并确保它们在插入或更新时具有适当的值。另一个是您将relationship()用于管理外键属性,并且您将确保 SubWidget() 对象的创建伴随着将其与您创建的父 Widget() 对象相关联的操作和/或单独获得。

关于级联,虽然不是必需的,但在适用的那些外键上具有 ON DELETE CASCADE 是一个好主意。在 SQLAlchemy 方面,使用时relationship()您通常希望向 ORM 提示数据库将通过passive_deletes 标志级联删除(http://www.sqlalchemy.org/docs/orm/collections.html?highlight=passive_deletes#using -passive-deletes ),但这通常是性能增强;否则,SQLAlchemy 会确保在依赖端表示的所有对象relationship()都加载到内存中,并进行适当处理,这意味着将外键属性设置为 NULL(默认值)或将依赖对象标记为删除(由将“级联”设置为“全部,删除孤儿”,请参见http://www.sqlalchemy.org/docs/orm/session.html#cascades)。

ON UPDATE 级联不太常见,因为自然主键如今已不常见,因为它们实际上不如普通整数主键执行得好,并且在其他方​​面也很麻烦。然而,SQLAlchemy 也支持这些,它们通常会自行处理,因为 SQLA 默认情况下假定发生 PK 突变时更新级联已经到位,请参阅http://www.sqlalchemy.org/docs/orm/relationships .html#mutable-primary-keys-update-cascades以获得详细描述。

也许这一切都更容易通过一些实验来理解,基本思想是 SQLAlchemy 只发出你告诉它的 SQL,即使它的许多 SQL 行为一旦预先配置就自动化了。 relationship()应该配置详细信息,说明您希望它在根据数据库中存在的约束保存、修改或删除数据时如何表现。

于 2011-09-29T22:24:31.790 回答
1

因此,基于 zzzeeks 的答案,以及在我最初的问题之后我自己的学习/修补......

为了使 SQLAlchemy 主动防止数据库状态的会话中视图可能会偏离数据库在刷新/提交时允许的内容,您必须在 SQLAlchemy 模型中镜像数据库模式中找到的所有约束。

这是通过以下形式的列定义完成的:

ForeignKey(..., onupdate='', ondelete='')
primary_key=True
unique=True

依此类推,可能包含 __table_args__,例如:

__table_args__ = (
        ForeignKeyConstraint(['id'], ['remote_table.id']),
        UniqueConstraint('foo'),
        )

对于约束跨越多列的情况。

然而:

relationship()

及其相关论点,例如:

cascade
cascade_backrefs
foreign_keys
passive_deletes
passive_updates

等等,是一个(重要的)便利功能,它允许您以尽可能少的努力使用您的模型,但最终并不是为了防止破坏参照完整性。

relationship() 功能不能表达数据库中的所有典型约束,而 Column()(和 __table_args__)功能可以。

另一方面,使用上面列出的一些参数(或在最有意义的地方使用默认值)配置关系(),将使 SQLAlchemy 自动执行任务,最终可以说是与引用整数相关的。否则通常必须通过周围代码中的逻辑来表达。

在某些情况下,relationship() 的最佳配置也将避免 SQLAlchemy 发出不必要的 SQL 语句。

希望这个总结有点准确......

于 2011-09-30T13:04:47.960 回答