仅在事务完成后才会触发post_save信号

dot*_*oto 9 api django transactions django-signals django-models

我编写了一些API,其中各个函数在事务块中执行.我在save()一个/几个Model/s的实例/ s上调用该方法(经过一些修改),并且还在Elasticsearch中连续索引实例/ s的一些JSON相关信息.我希望数据库回滚,即使由于某种原因save(),其中一个实例或索引到Elasticsearch失败.

现在,出现的问题是,即使在事务块内部,post_save()信号也会被调用,这是一个问题,因为某些通知是从这些信号中触发的.

有没有办法post_save()在交易成功完成后触发信号?

Mic*_*Tom 7

我认为最简单的方法是使用transaction.on_commit()。这是一个使用models.Model子类的示例,该子类Photo仅在当前事务结束后才与Elasticsearch对话:

from django.db import transaction
from django.db.models.signals import post_save

@receiver(post_save, sender=Photo)
def save_photo(**kwargs):
    transaction.on_commit(lambda: talk_to_elasticsearch(kwargs['instance']))
Run Code Online (Sandbox Code Playgroud)

请注意,如果transaction.on_commit()在不在活动事务中执行获取时,它将立即运行。


Rob*_*oba 6

并不是的。该信号与db事务的成功或失败无关,但与save方法本身无关-在调用之前,您触发了pre_save信号,在调用之后,您触发了post_save信号。

这里有2种方法:

  • 您将在post_save方法中检查实例,并确定模型是否成功保存;最简单的方法:在save方法中,在事务成功执行之后,用一个标记(说)注释您的实例instance.saved_successfully = True,您将在post_save处理程序中对其进行测试。
  • 您将放弃post_save信号并为您自己创建一个自定义信号,您将在事务成功运行后触发该信号。

说得通?

聚苯乙烯

如果您严格需要绑定到事务提交信号,请查看以下程序包:https : //django-transaction-hooks.readthedocs.org/en/latest/ ; 似乎该功能已集成在Django 1.9a中。

  • 信号包含在事务中 /sf/ask/2543222741/ (2认同)

Chr*_*rry 6

我遇到了 Django 管理员的严重问题,当父对象有内联子项被修改时,不允许在父对象上进行 post_save 事务。

这是我对抱怨在原子块中间进行查询的错误的解决方案:

def on_user_post_save_impl(user):
     do_something_to_the_user(user)

def on_user_post_save(sender, instance, **kwargs):
    if not transaction.get_connection().in_atomic_block:
        on_user_post_save_impl(instance)
    else:
        transaction.on_commit(lambda: on_user_post_save_impl(instance))
Run Code Online (Sandbox Code Playgroud)