在Python代码库中混合SQLAlchemy和Django并保持事务完整性

时间:2014-10-14 16:49:48

标签: django sqlalchemy pyramid

我有一个项目,我希望(需要?)在同一个Web代码库中混合SQLAlchemy模型,Django模型和相应的ORM。我希望默认情况下有原子请求,并将SQLAlchemy事务生命周期与Django请求和Django事务管理器联系起来。

是否存在现有技术如何使SQLAlchemy使用Django /连接和事务机制,反之亦然?

这种整合工作的起点是什么?有什么限制,例如如果您尝试重用相同的数据库连接?

缩小问题范围:

  • Django ORM和SQLAlchemy ORM不会触及相同的表格

  • 在第一步,我所关心的是当HTTP请求结束时,两个事务管理器以某种连贯的方式提交,例如如果Django提交事务SQLAlchemy也

  • 我怎么能说SQLAlchemy使用为Django配置的数据库连接?

  • 我可以将SQLAlchemy会话绑定到Django事务管理器吗?当Django打开数据库连接时,我可以打开一个新的SQLAlchemy会话并将其绑定到打开的Django事务?当Django提交时,我可以发出SQLAlchemy的信号来刷新它的东西,所以它沿着同样的cmmit。 Django 1.6在原子事务中引入了新的语义,所以这可能会有所帮助。

1 个答案:

答案 0 :(得分:4)

这真的不容易。我想知道这项努力是否值得。 SQLAlchemy和Django使用非常不同的抽象和模式来处理对象持久性和事务。

Django ORM遵循Active Record模式,其中对象更直接地映射到数据库表并封装所有访问和逻辑。当您调用`save()'方法时,对象中的更改会直接转换为SQL代码更改的行。您可以自己管理事务,但一切基本上只是处理底层数据库的语法糖。

SQLAlchemy遵循Data Mapper模式,其中有另一层抽象,负责在活动对象和数据库之间移动数据,彼此独立。对象甚至不知道存在数据库,并且对象和数据库表之间的映射非常非常灵活。此外,SQLAlchemy在Python端有另一个事务层,遵循Unit of Work模式,它基本上将整个SQL事务封装为原子实体。通过主键在会话中跟踪对象,并以正确的顺序原子保存更改。

来自Django,我第一次使用Flask和SQLAlchemy时,很多人都犯了一个错误,就是试图模仿SQLAlchemy上Django ORM的使用模式。例如,当你习惯使用Django-ORM时,创建一个提交事务的save()方法看起来很明显,但这在SQLAlchemy中是一个糟糕的想法。我很难理解他们如何不能很好地融合。

SQLAlchemy声明性基本方法封装了class-mapper-table关系并使其看起来更像ActiveRecord模式,但这可能会产生误导,因为您开始认为对象本身具有数据库知识。

如果您真的需要这样做,考虑到SQLAlchemy语义如何更清晰地映射到数据库,我认为最好的办法是将SQLAlchemy本身作为数据库处理并创建一个SQLAlchemy后端,它知道如何将Django模型和查询映射到SQLAlchemy model-mapper-table。也许您甚至可以将Django模型本身与SQLAlchemy映射器表一起使用。

因此,例如,当您在Django中运行save()方法时,它应该从当前会话中检索并更改等效的SQLAlchemy对象,而不是在数据库中生成和运行SQL,因此任何处理SQLAlchemy层上的对象将所有内容视为数据库。在Django中提交事务时,您提交SQLAlchemy会话。

这可能是一项有趣的练习,但对于真实世界的用例,我真的没有太多意义。

更新答案

看起来你想要的只是将Django事务与SQLAlchemy会话同步。您无需为此共享连接实例。您可以使用django-transaction-hooks之类的东西来触发负责提交SQLAlchemy会话的回调。如果需要执行相反操作,在提交SQLAlchemy会话时提交Django事务,则可以使用after_commit事件。

请注意,两个引擎之间不会存在原子性。如果在SQLAlchemy提交中出现错误,则无法回滚Django提交,反之亦然。