[Answered ]-Django listener isn't hearing the signal

1👍

✅

It might be that the sender should be the User class:

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

1👍

The answer given by alecxe is the accepted answer.

I am only adding this answer to help newbies like me understand what happened here, and to provide an alternate solution of changing the listener without changing the package code.

Thanks a million to @alecxe for that answer. That was the key that finally helped me wrap mind around the process. The docs did not help me much in this case, and it seems that many others have difficulty with signals as well.

The key is that sender in the send() tuple must match sender in your connect() tuple.

In this case, there was no problem with the sender. The problem was that my listener was listening for the right signal, but for the wrong sender. Changing the send() tuple worked, but I would rather fix my broken listener than to modify the sender in the registration package. The challenge there was, with my inexperience, I didn’t know how sender=self.__class__ would appear when output. Using PyCharm, with a breakpoint, I was able to get that answer.

I’ll detail how I did, just in case there is someone out there who could benefit from it.

Using alexce’s answer, my signal listener was working, so I was able to place a breakpoint inside create_user_profile(). That pauses the program while the signal is still in memory. At that point, the signal can be seen in the variables list in the debugger.

I added 'check_signal' to the Signal args in signals.py:

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

…and then self.__class__ was added back into the send() call:

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

When debugging, the value of check_signal was <registration.backends.default.views.ActivationView>.

So the solution for fixing my listener without modifying the sender was first to restore the original code in registration/signals.py:

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

…and restore the code in registration/default/views.py:

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

…and finally, to fix the listener in 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)

There may be a way to do this without having to import ActivationView, but I’m not sure. It does work this way. For anyone using django-registration-redux with the simple (no email) configuration, the only differences would be from registration.backends.simple.views import RegistrationView and the listener would be user_registered.connect(create_user_profile, sender=RegistrationView).

And just in case anyone is curious, here is the code from 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()

I spent days of madness and desperation acquiring the logic behind these seven little lines of code. I hope this can save someone else from such stress.

Leave a comment