在 Django 中,如何在组添加或删除用户时获取信号?

发布于 2024-12-12 08:30:27 字数 158 浏览 0 评论 0原文

在 Django 管理中,我有时会向(现有)组添加或删除用户。当发生这种情况时,我希望能够运行一个函数。

我只是使用标准的用户和组模型。

我已经考虑过通过 m2m_changed 使用信号来完成此操作,但似乎需要一个 Through 类 - 我认为在这种情况下没有一个。

In the Django admin I sometimes add or delete users to or from (existing) groups. When this happens I'd like to be able to run a function.

I'm just using the standard User and Group models.

I have looked at doing it with signals, through m2m_changed, but it seems to need a Through class - and I don't think there is one in this case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

丢了幸福的猪 2024-12-19 08:30:27

来自 django 文档

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_clearpost_clearpre_addpost_add。使用这些信号的组合,您可以存储前组和后组。通过对这些列表进行比较,您可以为用户删除和添加组。

请注意,当编辑组而不是用户时,信号是相反的(pk_setinstance)。

From the django doc:

sender - The intermediate model class describing the ManyToManyField. This class is automatically created when a many-to-many field is defined; you can access it using the through attribute on the many-to-many field.

When subscribing to m2m_changed like so:

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

You will receive a bunch of signals like this (shortened):

{'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'}

So the user bouke has been added to pk_set groups: [1]. However I noted that the admin layout clears all groups and then adds the selected groups back in. The signals you will receive are pre_clear, post_clear, pre_add, post_add. Using a combination of these signals you could store the pre and post groups. Doing a diff over these lists, you have the deleted and added groups for the user.

Note that the signals are the other way around (pk_set and instance) when editing a group instead of a user.

深白境迁sunset 2024-12-19 08:30:27

您将在 Django 文档中看到< /a> (v1.11) 您所需的发件人应该是属于 ManyToMany 字段的中间 through 字段,无论在何处定义。如果您将其注册为发件人,那么您将听到例如用户向自己添加组以及组向自己添加用户的声音。

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 deleted their relation to groups «%s»", instance.username, pk_set)
        if action == 'post_remove':
            # The *modification* happening is a deletion of the link
            …
        elif action == 'post_add':
           logger.info("User %s created a relation to groups «%s»", instance.username, ", ".join(pk_set))
            …
    else:
        logger.info("Group %s is modifying its relation to users «%s»", instance, pk_set)
        …
    return

You'll see in the Django documentation (v1.11) that your desired sender should be the intermediate through field belonging to the ManyToMany field, wherever that's defined. If you register that as your sender, then you'll be listening to eg Users adding Groups to themselves, as well as Groups adding Users to themselves.

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 deleted their relation to groups «%s»", instance.username, pk_set)
        if action == 'post_remove':
            # The *modification* happening is a deletion of the link
            …
        elif action == 'post_add':
           logger.info("User %s created a relation to groups «%s»", instance.username, ", ".join(pk_set))
            …
    else:
        logger.info("Group %s is modifying its relation to users «%s»", instance, pk_set)
        …
    return
风启觞 2024-12-19 08:30:27

您需要使用 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)

You need to create a signal using m2m_changed as a receiver. According to the official Django documentation:

A signal is sent when a ManyToManyField is changed on a model instance. Strictly speaking, this is not a model signal since it is sent by the ManyToManyField.

So, the simplest implementation is as follows:

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

In your case, you want to perform something when a user is added or removed from a group, so you can take advantage of the action parameter when it takes the values 'pre_add', 'post_add', 'pre_remove', and 'post_remove'. You can also take advantage of pk_set parameter which contains primary key values that have been added to or removed from the relation.

@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)
走走停停 2024-12-19 08:30:27

尝试使用 django-celery 来实现这一点可能会更好,这样您就可以编写自定义任务,并且根据特定条件(例如删除或添加)您可以触发特定任务。

It might be better to try and achieve this with django-celery, that way you can write custom tasks, and based on a certain criteria (such as removal or addition) you can fire of a certain task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文