在配置SQLAlchemy模型时,有人可以帮助我获得大图,因此可以确保所有级别的参照完整性吗?
我认为应该由DB表达和强制执行参照完整性,我已经创建了一个模式(目前在Postgresql中),其中包含我认为需要的所有约束,从而为我提供了一个我信任的数据库将强制引用完整性。
然后我开始在声明模式下使用SQLAlchemy(0.7)在此DB上构建应用程序。
经过搜索和阅读,我了解到我可以配置:
并且所有这些选项都有默认值。
但是我对我的SQLAlchemy模型实际需要做多少感到困惑,以确保SQLAlchemy在会话期间不会与数据库及其约束失去同步。
如果我在SQLAlchemy的Columns()定义中配置'onupdate'等,我到底实现了什么?
对于cascade和passive_delete / passive_update规则,我可以配置关系()。我在这需要什么,为什么?
或者重新解释我的问题:SQLAlchemy将在多大程度上了解数据库架构中配置的约束,以及在模型中重复它们的范围(以及如何)?
还有什么我应该知道的吗? :)
答案 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语句。
希望这个总结有点准确......