2012-07-27 74 views
6

我需要檢測post_remove信號的錯誤,所以我寫了:信號m2m_changed與post_remove

def handler1(sender, instance, action, reverse, model, pk_set, **kwargs): 
if (action == 'post_remove'): 
    test1() # not declared but make a bug if it works, to detect :) 

m2m_changed.connect(handler1, sender=Course.subscribed.through) 

如果我用「post_add」這是確定..改變「post_remove」它是一個Django的bug關於post_remove ??

我使用的模型和我切換beetween的「訂閱」兩個值(所以一加,一個刪除)

class Course(models.Model): 
    name = models.CharField(max_length=30) 
    subscribed = models.ManyToManyField(User, related_name='course_list', blank=True, null=True, limit_choices_to={'userprofile__status': 'student'}) 

我已經看到了使用Django的錯誤後,也許它沒有帶過固定...(或它是我^^)

回答

5

據我瞭解,這不是一個錯誤,它只是,Django不按照你期望的方式更新m2m關係。它不刪除要刪除的關係,然後添加新的關係。相反,它清除所有的m2m關係,然後再添加它們。

有一個相關的問題Django signal m2m_changed not triggered它鏈接到票13087

所以,你可以檢查與m2m_changed信號pre_clearpost_clear行動,而是因爲這些行爲不提供pk_set,它不會幫你找到的相關條目保存之前,你想在your other question做。

+0

我真的不知道該怎麼辦,我需要婁代碼

要做...我不能使用信號,要麼.save()覆蓋..我需要從模型字段(M2M)中刪除用戶,如果他從另一個模型的字段(M2M)中刪除... – nlassaux 2012-07-27 11:48:36

+4

I'我不確定最好的方法。您可以嘗試使用'pre_save'信號將實例上的相關對象存儲到實例中。 'instance._old_m2m = list(instance.subscribed.values_list('pk',flat = True))'。然後在你的'post_add'信號處理器中,比較'pk_set'和'instance._old_m2m'。祝你好運! – Alasdair 2012-07-27 12:05:16

+0

是的,我已經考慮過了,但它並沒有真正優化:/我會搜索... – nlassaux 2012-07-27 12:12:35

6

感謝Alasdairscomment我找到了解決方案,並將它發佈在這裏 - 也許有人可以使用它。

models.py

class Team(models.Model): 
    name = models.CharField(max_length=100) 
    members = models.ManyToManyField(User) 

pre_save.connect(team_pre_save, sender=Team) 
m2m_changed.connect(team_members_changed, sender=Team.members.through) 

signals.py

def team_pre_save(sender, instance, **kwargs): 
    if instance.pk: 
     instance._old_m2m = set(list(instance.members.values_list('pk', flat=True))) 
    else: 
     instance._old_m2m = set(list()) 

def team_members_changed(sender, instance, **kwargs): 
    if kwargs['action'] == "post_clear": 
     # remove all users from group 
     group = Group.objects.get(name='some group') 
     for member in instance._old_m2m: 
      user = User.objects.get(pk=member) 
      user.groups.remove(group) 

    if kwargs['action'] == "post_add": 
     added_members = list(kwargs['pk_set'].difference(instance._old_m2m)) 
     deleted_members = list(instance._old_m2m.difference(kwargs['pk_set'])) 

     if added_members or deleted_members: 
      # we got a change - do something, for example add them to a group? 
      group = Group.objects.get(name='some group') 

      for member in added_members: 
       user = User.objects.get(pk=member) 
       user.groups.add(group) 

      for member in deleted_members: 
       user = User.objects.get(pk=member) 
       user.groups.remove(group) 
1

我有後得出結論,很長很長的時間Øseaching 首先我的問題:我有一些如何更新一個我的模型的屬性設置爲False,當我的m2m爲空時,如果它至少有一個項目,則爲true,所以,真實的工作,但當我嘗試「pre_remove」或「post_remove」永遠不會觸發,所以經過一些trys與一些不同的例子後,我看到了這個「pre_clear」怪異的東西,每次我改變我的M2M這總是有最後的值,所以我設法強制刪除這個值從我的M2M,這樣它觸發pre_remove和post_remove,所以這對我的作品,看到那麼現在我可以全自動設置ativo真或假基於我M2M

class Servico(BaseMixin): 
    descricao = models.CharField(max_length=50) 

#This inheritance from User of django that has is_active boolean field 
class UsuarioRM(Usuario): 
    servicos = models.ManyToManyField(Servico,related_name='servicos_usuario', blank=True) 

# SIGNALS 
from django.db.models import signals 
from django.db.models.signals import m2m_changed 

def usuariorm_servicos_changed(sender, **kwargs): 
    action = kwargs.pop('action', None) 
    pk_set = kwargs.pop('pk_set', None) 
    instance = kwargs.pop('instance', None) 

    if action == "pre_clear": 
     if instance.servicos.all(): 
     servicos = instance.servicos.all() 
      for servico in servicos: 
       instance.servicos.remove(servico) 
      instance.save() 
    else: 
     instance.is_active = False 
     instance.save() 
     if action == "post_add": 
      if pk_set: 
      instance.is_active = True 
     else: 
      instance.is_active = False 

     instance.save() 

m2m_changed.connect(usuariorm_servicos_changed, sender=UsuarioRM.servicos.through)