Экземпляр 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.

Вернуться на верх