save() 方法是不是异步提交更改?

Posted

技术标签:

【中文标题】save() 方法是不是异步提交更改?【英文标题】:Is save() method commiting changes asynchronously?save() 方法是否异步提交更改? 【发布时间】:2016-06-16 17:49:29 【问题描述】:

我有一个带有 Django Admin (v. 1.9.2) 的简单 class 模型,如下所示:

from django.contrib.auth.models import User

class Foo(models.Model):
    ...
    users = models.ManyToManyField(User)
    bar = None

我也像这样重载了save() 方法:

def save(self, *args, **kwargs):
    self.bar = 1

    async_method.delay(...)

    super(Foo, self).save(*args, **kwargs)

这里的async_method 是对将在 Celery 上运行的任务的异步调用,它采用 users 字段并向其添加一些值。

同时,每当将用户添加到ManyToManyField 时,我想根据bar 字段的值执行操作。为此,我定义了一个m2m_changed 信号:

def process_new_users(sender, instance, **kwargs):
    if kwargs['action'] == 'post_add':
        # Do some stuff
        print instance.bar

m2m_changed.connect(process_new_users, sender=Foo.users.through)

这就是问题所在。虽然我在save()方法内部和调用异步方法之前更改了bar的值,但是当process_new_users()方法被触发时,instance.bar仍然是None(初始值)。

我不确定这是否是因为 save() 方法异步提交更改,并且当 process_new_users() 被触发时,它尚未提交更改并且正在检索旧值,或者我是否缺少其他内容。

我的假设正确吗?如果是这样,有没有办法强制同步提交save() 中的值,以便我可以然后调用异步方法?

注意:也欢迎任何实现此目的的替代方法。


更新 1:在 @Gert 的回答中,我实现了 transaction.on_change() 触发器,因此每当保存 Foo 实例时,我都可以安全地调用异步函数。为此,我实现了这个:

bar = BooleanField(default=False)   # bar has became a BooleanField

def call_async(self):
    async_method.delay(...)

def save(self, *args, **kwargs):
    self.bar = True

    super(Foo, self).save(*args, **kwargs)

    transaction.on_commit(lambda: self.call_async())

不幸的是,这并没有改变。我现在得到的是False,而不是None,而我应该在m2m_changed 信号中得到True

【问题讨论】:

save() 方法不会异步提交更改。您在模型(同步)保存之前调用异步任务,因此它可能会或可能不会在模型实际保存后运行。 @knbk 一旦save() 方法成功保存了模型更改,我可以以任何方式运行异步任务吗? (不确定这里是否有 save()post-save 钩子...) 【参考方案1】:

您想确保您的数据库是最新的。在 Django 1.9 中,有一个新的transaction.on_commit 可以触发 celery 任务。

【讨论】:

谢谢。正如我所看到的,没有定义 who 实际触发了钩子 - 我的意思是,有没有办法明确定义只有在 save() 方法已提交其更改时才应触发该方法? @nKn Django 事务系统会触发它。它知道事务何时实际提交到数据库中。 很好,我会试一试并报告结果。谢谢。 似乎传递给on_commit的触发方法不接受参数,我也无法设法传递它self。你有一个例子如何使用on_commit触发器inside一个类? @nKn 我相信这是可能的:transaction.on_commit(lambda: async_method.delay(self.id))

以上是关于save() 方法是不是异步提交更改?的主要内容,如果未能解决你的问题,请参考以下文章

提交更改后,是不是有通用方法让 EF 返回新模型数据和关联的模型数据?

mongoose中Documents的save方法

带有自动提交事务的 Django save() 行为

异步猪作业提交

同步Postgres和ElasticSearch的最佳方法是什么?

异步执行 SQL 或从触发器更改锁定