В Django, как я могу получить сигнал, когда в группу добавлен или удален пользователь? - PullRequest
3 голосов
/ 26 октября 2011

В админке Django я иногда добавляю или удаляю пользователей в или из (существующих) групп.Когда это происходит, я хотел бы иметь возможность запускать функцию.

Я просто использую стандартные модели пользователей и групп.

Я смотрел на это с помощью сигналов, через m2m_changed, но, похоже, нужен сквозной класс - и я не думаю, что в этом случае он есть.

Ответы [ 4 ]

6 голосов
/ 24 ноября 2011

Из django doc :

sender - Промежуточный класс модели, описывающий ManyToManyField.Этот класс создается автоматически при определении поля «многие ко многим»;Вы можете получить к нему доступ, используя атрибут through в поле «многие ко многим».

При подписке на m2m_changed, например, так:

@receiver(m2m_changed)
def my_receiver(**kwargs):
    from pprint import pprint
    pprint(kwargs)

Вы получите несколько сигналов, например:это (сокращенно):

{'sender': <class 'django.contrib.auth.models.User_groups'>,
 'action': 'post_add',
 'instance': <User: bouke>,
 'model': <class 'django.contrib.auth.models.Group'>,
 'pk_set': set([1]),
 'reverse': False,
 'signal': <django.dispatch.dispatcher.Signal object at 0x101840210>,
 'using': 'default'}

Таким образом, пользователь bouke был добавлен в pk_set группы: [1].Однако я отметил, что макет администратора очищает все группы, а затем добавляет выбранные группы обратно. Полученные вами сигналы: pre_clear, post_clear, pre_add, post_add.Используя комбинацию этих сигналов, вы можете сохранить группы до и после записи.При выполнении сравнения этих списков у вас есть удаленные и добавленные группы для пользователя.

Обратите внимание, что сигналы противоположны (pk_set и instance) при редактировании группы вместо пользователя..

1 голос
/ 10 апреля 2018

Вам необходимо создать сигнал, используя m2m_changed в качестве приемника.Согласно официальной документации Django :

Сигнал отправляется при изменении ManyToManyField на экземпляре модели.Строго говоря, это не модельный сигнал, поскольку он посылается ManyToManyField.

Итак, простейшая реализация выглядит следующим образом:

@receiver(m2m_changed)
def signal_handler(**kwargs):
    from pprint import pprint
    pprint(kwargs)

В вашем случаеВы хотите что-то выполнить, когда пользователь добавлен или удален из группы, поэтому вы можете воспользоваться параметром action, когда он принимает значения 'pre_add', 'post_add', 'pre_remove' и 'post_remove'.Вы также можете воспользоваться параметром pk_set, который содержит значения первичного ключа, которые были добавлены или удалены из отношения.

@receiver(m2m_changed)
def signal_handler_when_user_is_added_or_removed_from_group(action, instance, pk_set, model, **kwargs):
    if model == Group:
        if action == 'pre_add':
            # TODO: add logic
            pass
        elif action == 'post_add':
            # TODO: add logic
            pass
        # handle as many actions as one needs
    # The following for loop prints every group that were
    # added/removed.
    for pk in pk_set:
        group = Group.objects.get(id=pk)
        print(group)
0 голосов
/ 26 июня 2018

В документации Django (v1.11) вы увидите, что желаемым отправителем должно быть промежуточное поле through, принадлежащее полю ManyToMany, где бы оно ни было определено. Если вы зарегистрируете это в качестве отправителя, вы будете слушать, например, пользователей, добавляющих группы к себе, а также группы, добавляющих пользователей к себе.

self.walrus.groups.remove(self.peon_group)

@receiver(signal=m2m_changed, sender=User.groups.through)
def adjust_group_notifications(instance, action, reverse, model, pk_set, using, *args, **kwargs):
    if model == Group and not reverse:
        logger.info("User %s is modifying their relation to groups «%s»", instance.username, pk_set)
        …
        # Walrus example fits here
    else:
        logger.info("Group %s is modifying its relation to users «%s»", instance, pk_set)
        …
    return
0 голосов
/ 26 октября 2011

Возможно, лучше попытаться достичь этого с помощью django-celery, чтобы вы могли писать собственные задачи, а на основе определенных критериев (таких как удаление или добавление) вы можете запускать определенную задачу.

...