6

我需要检测一个 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_remove' 更改为 'post_add' 就可以了。这是 django 关于 post_remove 的错误吗?

我使用该模型并在两个“订阅”值之间切换(因此添加一个,删除一个)

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 的错误,也许它还没有被修复......(或者是我 ^^)

4

3 回答 3

7

据我了解,这不是错误,只是 Django 没有按照您期望的方式更新 m2m 关系。它不会删除要删除的关系然后添加新的关系。相反,它会清除所有 m2m 关系,然后再次添加它们。

有一个相关的问题Django signal m2m_changed not trigger which links to ticket 13087

因此,您可以使用信号检查 pre_clearorpost_clear操作m2m_changed,但由于这些操作不提供,因此它无法帮助您在保存之前找到相关条目,就像您在其他问题pk_set中想要做的那样。

于 2012-07-27T11:34:24.973 回答
6

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

模型.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)

信号.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)
于 2012-10-16T12:28:16.943 回答
2

经过长时间的搜索,我得出了一个结论首先我的问题:我有一些如何从我的模型中更新一个属性以在我的 m2m 为空时将其设置为 False,如果它至少有 1 个项目,则为 true,所以,真正的事情有效,但是当我尝试“pre_remove”或“post_remove”时永远不会被触发,所以在尝试了一些不同的例子后,我在这个“pre_clear”上看到了一些奇怪的东西,每次我改变我的m2m这总是有最后一个值,所以我设法从我的 m2m 中强制删除这些值,这样它会触发 pre_remove 和 post_remove,所以这对我有用,请参见下面的代码

所以现在我可以根据我的 m2m 自动设置 ativo True 或 False

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 )
于 2016-09-05T13:30:48.723 回答