Python django:commit和raiseinsidetransaction.atomic()中的

Python django:commit和raiseinsidetransaction.atomic()中的,python,django,transactions,django-orm,Python,Django,Transactions,Django Orm,我们正在尝试从commit_手动迁移到atomic,以便在遗留项目中至少将Django升级到1.8。在大多数情况下,我们需要这样做: with transaction.atomic(): obj = Entity.objects.select_for_update().get(pk=pk) try: obj.do_something() obj.set_some_status() obj.save() except Some

我们正在尝试从
commit_手动
迁移到
atomic
,以便在遗留项目中至少将Django升级到1.8。在大多数情况下,我们需要这样做:

with transaction.atomic():
    obj = Entity.objects.select_for_update().get(pk=pk)
    try:
        obj.do_something()
        obj.set_some_status()
        obj.save()
    except SomeException:
        obj.set_failed_flag()
        obj.save()
        raise
因为被调用方需要此异常信息才能继续执行特定流。但是在这种情况下,事务/保存点将回滚,这不是我们想要的,因为我们想要提交
obj.set\u failed\u flag()
。而且,将它设置在同一个原子块内似乎也是合乎逻辑的,因为我们已经为这个对象锁定了一行

有什么想法/模式吗?提前谢谢

另外,使用旧的手动事务管理非常简单


p.p.S.我们也将异常用于“提前退出”,移动到某些标志等会带来混乱,我个人希望避免这种情况。

假设
SomeException
不是数据库异常,您可以将其保存并在原子块外提升:

with transaction.atomic():
    obj = Entity.objects.select_for_update().get(pk=pk)

    try:
        obj.do_something()
        obj.set_some_status()
    except SomeException as e:
        obj.set_failed_flag()
        exception = e
    else:
        exception = None

    obj.save()

if exception:
    raise exception
如果您觉得这太冗长,需要经常这样做,您可以编写一个上下文管理器,作为
transaction.atomic()
的代理,但在某些情况下不会触发回滚


最后,请注意,Django仍然有。

除了已经发布的答案之外,如果有嵌套方法在链中较高的位置启动原子块,则使用以下方法会有所帮助:

transaction.on_commit(lambda: method_that_raises_exception())

这样,在事务提交后会引发异常。

谢谢Kevin,这种方法正是我所想的,事实上我希望避免的。我在考虑手动事务管理,但我们也使用保存点。原子()在这种情况下是一件好事。有没有办法用transaction.atomic处理分布式事务?@shadow0359恐怕我还不完全理解这个问题。您能进一步说明吗?我想使用事务进行两个独立的数据库连接。