Экземпляр m2m_changed при обратном движении
У меня есть следующий сигнал:
@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}")
Я могу запустить его, как и ожидалось, когда делаю:
User.cars.add(car)
Но если я также хочу удалить пользователя из кэша в этом случае, что мне делать?
Car.user_set.add(user)
поскольку в данном случае экземпляр является объектом Car, а не User.
Такие сигналы уже работают двунаправленно. Поэтому независимо от того, как вы добавите элемент
На самом деле это одно из предостережений m2m_changed
сигнала [Django-doc]: что sender
и instance
могут быть не только User
и Car
, но и Car
и User
, что усложняет написание сигнала.
@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
У kwargs
будет два дополнительных параметра, которые здесь интересны:
reverse
: что являетсяTrue
, если вы выполнили добавление/удаление/изменение с помощью связанного менеджера, так что в этом случаеmy_car.user_set.add(my_user)
; иpk_set
: который является набором добавленных/удаленных первичных ключей, так что в случаеmy_user.cars.add(my_car)
- набором с одним элементом: первичный ключmy_car
, а в случаеmy_car.user_set.add(my_user)
- множество с одним элементом: первичный ключmy_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.