仅在交易完成后触发 post_save 信号
Trigering post_save signal only after transaction has completed
我已经编写了一些 API,它们各自的功能在事务块中执行。我在a/severalModel/s的instance/s上调用了save()
方法(经过一些修改),并且还连续索引了[=25]的一些JSON相关信息=] 在 Elasticsearch 中。我希望数据库回滚,即使由于某种原因 save()
对于其中一个实例或对 Elasticsearch 的索引失败。
现在,问题出现了,即使在事务块内部,也会调用 post_save()
信号,这是一个问题,因为这些信号会触发一些通知。
有没有办法只在交易成功完成后触发 post_save()
信号?
不是真的。这些信号与 db t运行saction 成功或失败无关,但与 save 方法本身有关 - 在调用之前你有 pre_save 信号被触发,在调用之后你有 post_save 信号被触发。
这里有两种方法:
- 你将在post_save方法中检查实例并决定模型是否保存成功;最简单的方法:在 save 方法中,在 t运行saction 成功执行后,用标志注释您的实例,例如
instance.saved_successfully = True
,您将在 post_save 处理程序中对其进行测试。
- 您将放弃 post_save 信号并为您自己创建一个自定义信号,您将在 t运行 行动 运行 成功后触发。
有道理吗?
P.S.
如果您确实需要绑定到 t运行saction 提交信号,请查看此包:https://django-transaction-hooks.readthedocs.org/en/latest/;看起来该功能已集成到 Django 1.9a 中。
我遇到了严重的问题,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))
我认为最简单的方法是使用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']))
请注意,如果 transaction.on_commit()
在未处于活动事务中时执行,它将立即 运行。
我们正在使用这个小块:
def atomic_post_save(sender, instance, **kwargs):
if hasattr(instance, "atomic_post_save") and transaction.get_connection().in_atomic_block:
transaction.on_commit(lambda: instance.atomic_post_save(sender, instance=instance, **kwargs))
post_save.connect(atomic_post_save)
然后我们简单地在我们喜欢的任何模型上定义一个atomic_post_save
方法:
class MyModel(Model):
def atomic_post_save(self, sender, created, **kwargs):
talk_to_elasticsearch(self)
需要注意两点:
- 我们只在交易中调用
atomic_post_save
。
- 在流程中发送消息并将它们包含在
atomic_post_save
内部的当前请求中为时已晚。
我已经编写了一些 API,它们各自的功能在事务块中执行。我在a/severalModel/s的instance/s上调用了save()
方法(经过一些修改),并且还连续索引了[=25]的一些JSON相关信息=] 在 Elasticsearch 中。我希望数据库回滚,即使由于某种原因 save()
对于其中一个实例或对 Elasticsearch 的索引失败。
现在,问题出现了,即使在事务块内部,也会调用 post_save()
信号,这是一个问题,因为这些信号会触发一些通知。
有没有办法只在交易成功完成后触发 post_save()
信号?
不是真的。这些信号与 db t运行saction 成功或失败无关,但与 save 方法本身有关 - 在调用之前你有 pre_save 信号被触发,在调用之后你有 post_save 信号被触发。
这里有两种方法:
- 你将在post_save方法中检查实例并决定模型是否保存成功;最简单的方法:在 save 方法中,在 t运行saction 成功执行后,用标志注释您的实例,例如
instance.saved_successfully = True
,您将在 post_save 处理程序中对其进行测试。 - 您将放弃 post_save 信号并为您自己创建一个自定义信号,您将在 t运行 行动 运行 成功后触发。
有道理吗?
P.S.
如果您确实需要绑定到 t运行saction 提交信号,请查看此包:https://django-transaction-hooks.readthedocs.org/en/latest/;看起来该功能已集成到 Django 1.9a 中。
我遇到了严重的问题,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))
我认为最简单的方法是使用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']))
请注意,如果 transaction.on_commit()
在未处于活动事务中时执行,它将立即 运行。
我们正在使用这个小块:
def atomic_post_save(sender, instance, **kwargs):
if hasattr(instance, "atomic_post_save") and transaction.get_connection().in_atomic_block:
transaction.on_commit(lambda: instance.atomic_post_save(sender, instance=instance, **kwargs))
post_save.connect(atomic_post_save)
然后我们简单地在我们喜欢的任何模型上定义一个atomic_post_save
方法:
class MyModel(Model):
def atomic_post_save(self, sender, created, **kwargs):
talk_to_elasticsearch(self)
需要注意两点:
- 我们只在交易中调用
atomic_post_save
。 - 在流程中发送消息并将它们包含在
atomic_post_save
内部的当前请求中为时已晚。