﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
27462	"Clarify what's contained in m2m_changed's ""pk_set"" argument"	Seti	Carlton Gibson	"
A code of signal;

{{{

@receiver(m2m_changed, sender=Group.user_set.through)
def changed_m2m(sender, instance, action, reverse, model, pk_set, **kwargs):

    print('Signal ""{}"" | Users in group: {} | pk_set: {}'.format(action, instance.user_set.all(), pk_set))

}}}


Run code:


{{{
        g1 = Group.objects.all()[0]

        g1.user_set.add(UserModel.objects.all()[0])
        g1.user_set.add(UserModel.objects.all()[0])
        g1.user_set.add(UserModel.objects.all()[0])

        g1.user_set.remove(UserModel.objects.all()[0])
        g1.user_set.remove(UserModel.objects.all()[0])
        g1.user_set.remove(UserModel.objects.all()[0])
}}}


Results:

{{{
Signal ""pre_add"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""post_add"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""pre_add"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: set()
Signal ""post_add"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: set()
Signal ""pre_add"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: set()
Signal ""post_add"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: set()
Signal ""pre_remove"" | Users in group: <QuerySet [<User: Martin Rivera>]> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""post_remove"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""pre_remove"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""post_remove"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""pre_remove"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}
Signal ""post_remove"" | Users in group: <QuerySet []> | pk_set: {UUID('d0d4a1eb-d2c0-4a27-b9a6-a057a4fa25bc')}

}}}


If action == 'pre_remove', then pk_set has primary keys of objects which is not presets in a queryset of other model. It is an expected behaviour.

But if action == 'post_remove' then pk_set **always** contains primary keys of objects, even queryset is empty. Does is expected behaviour?

The Django`s docs says next:
https://docs.djangoproject.com/en/1.10/ref/signals/#m2m-changed

''pk_set
For the pre_add, post_add, pre_remove and post_remove actions, this is a set of primary key values that have been added to or removed from the relation.''

So, why the pk_set for the action == 'post_remove' always not empty?


I tested it on the Django 1.10 and the 1.9,  the result is same.
"	Cleanup/optimization	closed	Documentation	dev	Normal	fixed			Ready for checkin	1	0	0	0	0	0
