【发布时间】: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 钩子...)
标签: django asynchronous django-models celery