2012-07-27 78 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)