一个信号m2m_changed和post_remove的bug

nla*_*aux 6 django django-signals

我需要检测一个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)
Run Code Online (Sandbox Code Playgroud)

如果我用'post_add'改变'post_remove'就可以了..这是关于post_remove的django的错误吗?

我使用该模型并在两个'subscribed'值之间切换(所以添加一个,删除一个)

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'})
Run Code Online (Sandbox Code Playgroud)

我看过一篇有django错误的帖子,也许它还没有被修复......(或者它是我^^)

Ala*_*air 6

据我了解,这不是一个bug,只是Django没有按照你期望的方式更新m2m关系.它不会删除要删除的关系,然后添加新的关系.相反,它清除所有m2m关系,然后再添加它们.

有一个相关的问题Django信号m2m_changed未触发,它链接到票证13087.

因此,您可以使用信号检查 pre_clearpost_clear操作m2m_changed,但由于这些操作不提供pk_set,因此您无法在保存之前找到相关条目,如您在其他问题中所做的那样.

  • 我不确定最好的方法.您可以尝试使用`pre_save`信号在实例上存储相关对象,例如`instance._old_m2m = list(instance.subscribed.values_list('pk',flat = True))`.然后在`post_add`信号的处理程序中,将`pk_set`与`instance._old_m2m`进行比较.祝好运! (4认同)

Tho*_*rzl 6

感谢Alasdairs的 评论,我找到了解决方案并将其发布在此处 - 也许有人可以使用它.

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)