2016-03-03 75 views
1

我有一個名爲Contact的模型,它具有稱爲標籤的M2M關係。該模型有幾個booleanfields(在這個例子中是學生,alumus和員工)。更新model_save後更新M2M值

我想實現以下功能: 每次保存一個Contact對象後,我想檢查是否存在每個布爾型字段。如果它不存在,應該添加它。

我認爲這將與post_save掛鉤工作,這是我的代碼:

models.py然而

class Contact(BaseModel): 
    title = models.CharField(max_length=30, blank=True) 
    student = models.BooleanField(default=False) 
    alumnus = models.BooleanField(default=False) 
    employee = models.BooleanField(default=False) 
    tags = models.ManyToManyField(Tag) 

def update_tag(instance, tag_name, tagged): 
    tag, created = Tag.objects.get_or_create(name=tag_name, defaults={'deletable': False}) 
    if tagged: 
     instance.tags.add(tag) 
    else: 
     instance.tags.remove(tag) 

@receiver(post_save, sender=Contact, dispatch_uid="update_tags") 
def update_tags(sender, instance, **kwargs): 
    update_tag(instance, "Alumni", instance.alumnus) 
    update_tag(instance, "Students", instance.student) 
    update_tag(instance, "Employees", instance.employee) 

我注意到,這僅適用於如果我不包括我的標記字段在ModelForm對象中。如果包含,則所有更新都將被忽略。如果不包括,一切都按預期工作。

我做了一些研究和found,顯然M2M的關係有很大的不同:

當您保存通過管理形式它不是一個原子事務的典範。 主要對象首先被保存(以確保它具有PK),然後清除 M2M並將新值設置爲 表單中的值。因此,如果您處於主對象的save()中,那麼您在M2M尚未更新的 機會窗口中。實際上,如果您嘗試對M2M執行某些操作,則該更改將被clear()清除 。

但是,由於我沒有使用管理員表單,我不明白爲什麼這也發生在我的情況。有人知道我能如何解決我的問題嗎?

回答

0

這不僅僅是在管理形式,這發生在你保存任何Django模型的任何地方。

我沒有找到任何好的文檔鏈接到「爲什麼」,但我相信它與數據庫結構有關。在Django中,它存儲在一個模型中,但在數據庫級別,它創建了一個介於ContactTag(這是在數據庫級別執行此操作的正確方法)之間的中間表 - 它只是在Django內部隱藏。

而不是使用post_save信號,您需要使用m2m_changed信號,這將在ManyToMany字段發生更改時觸發。

+0

但問題是,我想檢查,每個模型保存後,如果布爾字段更改。如果這些布爾字段被更改,我想「同步」m2m字段。所以m2m_changed在我的情況下不起作用。 – hY8vVpf3tyR57Xib

+0

你最終實現了什麼解決方案? – wilbbe01