2016-03-03 81 views
1

我有一個簡單class模型Django管理(V 1.9.2。)是這樣的:save()方法提交異步更改?

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:作爲@格特的答案,我實現了一個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()) 

不幸的是,這並沒有改變。而不是None我現在得到False當我應該得到Truem2m_changed信號。

+0

'save()'方法不會異步提交更改。在模型(同步)保存之前,您正在調用異步任務,因此在模型實際保存後它可能運行也可能不運行。 – knbk

+0

@knbk任何方式我可以在save()方法成功保存模型更改後運行異步任務嗎? (不知道這裏是否有'save()'的*後保存*鉤子...) – nKn

回答

1

你想確保你的數據庫是最新的。在Django 1.9中,有一個新的transaction.on_commit可以觸發芹菜任務。

+0

謝謝。正如我所看到的那樣,沒有* who *實際觸發鉤子的定義 - 我的意思是,有沒有一種方法可以明確定義只有在save()方法提交了更改時才應該觸發該方法? – nKn

+0

@nKn Django事務系統會觸發它。它知道事務何時被實際提交到數據庫中。 – Gert

+0

不錯,我會試一試並報告結果。謝謝。 – nKn