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_add' で 'post_remove' を変更すれば問題ありません.. post_remove に関する Django のバグですか??

私はそのモデルを使用し、「購読済み」の 2 つの値を切り替えます (つまり、1 つが追加され、1 つが削除されます)。

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 リレーションをクリアしてから、再度追加します。

チケット13087にリンクする関連する質問Django signal m2m_changed not trigger があります。

そのため、信号でpre_clearorpost_clearアクションを確認できます が、これらのアクションは を提供しないため、他の質問でやりたかったように、保存する前に関連するエントリを見つけるのに役立ちません。m2m_changedpk_set

于 2012-07-27T11:34:24.973 に答える
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)

信号.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

私は長い間検索した後に結論に達しました最初の問題: モデルから1つの属性を更新して、m2mが空の場合はFalseに設定し、少なくとも1つのアイテムがある場合はtrueに設定する方法がありました。したがって、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 に答える