参照完整性 - 如何配置SQLAlchemy?

时间:2011-09-14 14:06:04

标签: sqlalchemy referential-integrity

在配置SQLAlchemy模型时,有人可以帮助我获得大图,因此可以确保所有级别的参照完整性吗?

我认为应该由DB表达和强制执行参照完整性,我已经创建了一个模式(目前在Postgresql中),其中包含我认为需要的所有约束,从而为我提供了一个我信任的数据库将强制引用完整性。

然后我开始在声明模式下使用SQLAlchemy(0.7)在此DB上构建应用程序。

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

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

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

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

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

对于cascade和passive_delete / passive_update规则,我可以配置关系()。我在这需要什么,为什么?

或者重新解释我的问题:SQLAlchemy将在多大程度上了解数据库架构中配置的约束,以及在模型中重复它们的范围(以及如何)?

还有什么我应该知道的吗? :)

2 个答案:

答案 0 :(得分:4)

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

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

因此假设“子小部件”上的FK引用“小部件”,您的应用程序需要确保数据处于正确的结构中。有两种方法可以做到这一点;一种是您手动维护包含外键引用的列,并确保它们在INSERT或UPDATE点具有适当的值。另一个是您使用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(默认值)或标记依赖对象之一删除(通过将“cascade”设置为“all,delete-orphan”发生,请参阅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行为在预先配置后都是自动化的。 {I} relationship()应该配置有关数据在数据库中存在的约束持久,修改或删除时的行为方式的详细信息。

答案 1 :(得分: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__)功能可以。

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

在某些情况下,关系()的最佳配置也会避免SQLAlchemy发布不必要的SQL语句。

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