【问题标题】:Django listener isn't hearing the signalDjango 监听器没有听到信号
【发布时间】:2015-03-09 05:51:14
【问题描述】:

我正在尝试在激活时(而不是在创建用户时)保存用户配置文件,但侦听器没有调用 create_user_profile()。监听器位于 models.py

from registration.signals import user_activated
from mysite.signals import create_user_profile

user_activated.connect(create_user_profile, sender=User)

我正在使用 django-registration-redux。我在注册过程中没有覆盖任何东西。在 registration/signals.py 中,信号是:

user_activated = Signal(providing_args=["user", "request"])

registration/default/views.py中有这个函数:

def activate(self, request, activation_key):
    """
    Given an an activation key, look up and activate the user
    account corresponding to that key (if possible).

    After successful activation, the signal
    ``registration.signals.user_activated`` will be sent, with the
    newly activated ``User`` as the keyword argument ``user`` and
    the class of this backend as the sender.

    """
    activated_user = RegistrationProfile.objects.activate_user(activation_key)
    if activated_user:
        signals.user_activated.send(sender=self.__class__,
                                    user=activated_user,
                                    request=request)

在 PyCharm 中,我在调用 send() 的最后一行放置了一个断点。当用户被激活时,执行会在该断点处暂停,并从那里继续,没有错误消息。就好像听者不在那里一样。

【问题讨论】:

    标签: python django django-signals


    【解决方案1】:

    可能发件人应该是User类:

    signals.user_activated.send(sender=activated_user.__class__,
                                user=activated_user,
                                request=request)
    

    【讨论】:

    • 只是为了扩展答案。检查this。我认为您应该使用“get_user_model”函数,这样您就不必在每次修改用户模型时都更改信号函数。这是正确的方法(我不知道包,但我猜他们重写了 User 类)
    • @djangozone 感谢您的提示。在这种情况下,用户模型没有以任何方式被覆盖。该软件包是旧 django-registration 的当前维护的分支。它只是创建一个 User 实例并使用默认的 User 属性,对 Django 的默认身份验证有很多改进。
    【解决方案2】:

    alecxe 给出的答案是公认的答案。

    我添加这个答案只是为了帮助像我这样的新手了解这里发生了什么,并提供在不更改包代码的情况下更改侦听器的替代解决方案。

    感谢@alecxe 的回答一百万。那是最终帮助我了解整个过程的关键。在这种情况下,文档对我没有太大帮助,而且似乎许多其他人也对信号有困难。

    关键是send() 元组中的sender 必须与connect() 元组中的sender 匹配。

    在这种情况下,发件人没有问题。问题是我的听众正在收听正确的信号,但收听了错误的发送者。更改 send() 元组有效,但我宁愿修复损坏的侦听器,也不愿修改注册包中的发件人。那里的挑战是,由于我缺乏经验,我不知道sender=self.__class__ 在输出时会如何出现。使用带有断点的 PyCharm,我能够得到答案。

    我会详细说明我是怎么做的,以防万一有人可以从中受益。

    使用 alexce 的答案,我的信号监听器正在工作,所以我能够在 create_user_profile() 内放置一个断点。这会在信号仍在内存中时暂停程序。此时,可以在调试器的变量列表中看到该信号。

    我在 signals.pySignal 参数中添加了 'check_signal'

    user_activated = Signal(providing_args=["user", "request", "check_signal",])
    

    ...然后self.__class__ 被添加回send() 调用中:

    signals.user_activated.send(sender=activated_user.__class__,
                                user=activated_user,
                                request=request,
                                check_signal=self.__class__)
    

    调试时check_signal的值为<registration.backends.default.views.ActivationView>

    所以在不修改发送者的情况下修复我的监听器的解决方案是首先恢复registration/signals.py中的原始代码:

    user_activated = Signal(providing_args=["user", "request"])
    

    ...并恢复registration/default/views.py中的代码:

    signals.user_activated.send(sender=self.__class__,
                                user=activated_user,
                                request=request)
    

    ...最后,在 models.py 中修复监听器:

    from registration.backends.default.views import ActivationView
    from registration.signals import user_activated
    from mysite.signals import create_user_profile
    
    user_activated.connect(create_user_profile, sender=ActivationView)
    

    可能有一种方法可以做到这一点,而不必导入 ActivationView,但我不确定。它确实以这种方式工作。对于使用简单(无电子邮件)配置的 django-registration-redux 的任何人,唯一的区别是 from registration.backends.simple.views import RegistrationView 和侦听器是 user_registered.connect(create_user_profile, sender=RegistrationView)

    如果有人好奇,下面是来自 mysite/signals.py 的代码:

    def create_user_profile(sender, user, **kwargs):
        """
        When user is activated, create the UserProfile. Prevents dead profiles
        from registered users who never activate.
        """
        from mysite.models import UserProfile
    
        UserProfile(user=user).save()
    

    我花了几天的疯狂和绝望来了解这七行代码背后的逻辑。我希望这可以帮助其他人摆脱这种压力。

    【讨论】:

      猜你喜欢
      • 2016-07-16
      • 1970-01-01
      • 2020-08-30
      • 1970-01-01
      • 1970-01-01
      • 2016-02-17
      • 2014-05-27
      • 2019-08-01
      • 2017-06-06
      相关资源
      最近更新 更多