【问题标题】:Referential Integrity - how to configure SQLAlchemy?参照完整性 - 如何配置 SQLAlchemy?
【发布时间】:2011-09-14 14:06:03
【问题描述】:

在配置 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 会在多大程度上了解数据库架构中配置的约束,以及我必须在多大程度上(以及如何)在我的模型中重复它们?

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

【问题讨论】:

    标签: sqlalchemy referential-integrity


    【解决方案1】:

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

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

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

    关于级联,虽然不是必需的,但在适用的外键上设置 ON DELETE CASCADE 是个好主意。在 SQLAlchemy 方面,当使用 relationship() 时,您通常希望通过 Passive_deletes 标志 (http://www.sqlalchemy.org/docs/orm/collections.html?highlight=passive_deletes#using-passive-deletes) 向 ORM 提示数据库将级联删除,但这通常是性能增强; 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() 应配置详细信息,说明您希望它在根据数据库中存在的约束对数据进行持久化、修改或删除时的行为方式。

    【讨论】:

    • 您好 zzzeek,感谢您尝试解除我脑海中的一些迷雾。而对于 SQLAlchemy 本身! :) 我为我自己的问题添加了一个“答案”,在那里我试图总结我认为我学到的东西。希望我走在正确的轨道上......
    【解决方案2】:

    所以,基于 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-17
    • 1970-01-01
    • 2016-03-13
    • 2010-09-26
    • 2013-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多