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.
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.
Share Improve this question edited Jan 19 at 19:36 willeM_ Van Onsem 477k33 gold badges472 silver badges609 bronze badges asked Jan 19 at 19:07 BazBaz 13.1k40 gold badges151 silver badges279 bronze badges1 Answer
Reset to default 0Such 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 isTrue
if 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.