M2m_changed instance when in reverse
I have the following signal:
@receiver(m2m_changed, sender=User.cars.through)
def car_added_to_user(sender, instance, action, **kwargs):
if action in ("post_add",):
cache.delete(f"user-{instance.pk}")
I can trigger it as expected when doing:
User.cars.add(car)
but if I also want to delete the user from the cache in this case, what do I do?
Car.user_set.add(user)
as in this case the instance is a Car object and not a User object.
Such signals already work bi-directional. So regardless how you add the element.
In fact this is one of the caveats of the m2m_changed signal signal [Django-doc]: that the sender and the instance can be a User and Car, but also a Car and User, so making it more complicated to write the signal.
@receiver(m2m_changed, sender=User.cars.through)
def car_added_to_user(sender, instance, action, **kwargs):
if action == 'post_add':
if issubclass(sender, User):
# did through my_user.cars.add(my_car)
cache.delete(f"user-{instance.pk}")
# my_user is the instance
elif issubclass(sender, Car):
# did through my_car.user_set.add(my_user)
# my_car is the instance
pass
The kwargs will have two additional parameters that are interesting here:
reverse: which isTrueif you did the add/remove/change by using the related manager, so in this casemy_car.user_set.add(my_user); andpk_set: which is a set of the primary keys added/removed, so in case ofmy_user.cars.add(my_car), a set with one element: the primary key ofmy_car, and in case ofmy_car.user_set.add(my_user), a set with one element: the primary key ofmy_user.
Note: Signals are often not a robust mechanism. I wrote an article [Django-antipatterns] that discusses certain problems when using signals. Therefore you should use them only as a last resort.