0

It's written in the doc that:

Another limitation of custom User models is that you can’t use django.contrib.auth.get_user_model() as the sender or target of a signal handler. Instead, you must register the handler with the resulting User model. See Signals for more information on registering an sending signals.

I guess it means you can do the following:

from django.contrib.auth import get_user_model

User = get_user_model()

@receiver(post_save, sender=User)
def user_saved(sender=None, instance=None, **kwargs):
    # something

Isn't it? I'm just wondering if I understand well (I don't understand why they say it's a "limitation", but whatever, just want to check).

lajarre
  • 4,910
  • 6
  • 42
  • 69

3 Answers3

6

It's because the object hasn't been "installed" when the signal is being created so get_user_model() can't find the object that it needs to attach the signal handler.

See this bug for the details on how it was found and what the problem is.

Your example wouldn't work because the get_user_model() call would fail for this reason. For now the only way to make a signal handler work with a custom User class is to name it directly without using get_user_model(), eg

@receiver(post_save, sender=myapp.MyUserModel) # can't use get_user_model() here
def user_saved(sender=None, instance=None, **kwargs):
    # something

Your coding style could also do with some work: when you run User = get_user_model(), that creates a variable called User with its value set to the results of the get_user_model() function call. Python convention (and that of most other languages) is for normal variables to start with a lower-case letter and for classes to start with an upper case letter.

So user = get_user_model() and then using the user variable later on would make much more sense to anyone reading your code and would help to avoid confusion in the future.

Brendan Quinn
  • 2,059
  • 1
  • 19
  • 22
  • Not sure what you're meaning about lower-case letters, User in this case is callable, or is a class, however you call that. Also, your point is right **when using get_user_model in the same models.py that the AUTH_USER_MODEL**. This is a good point, but your message is not clear – lajarre May 14 '13 at 17:02
3

That should work. I think they mean to use the same function as sender

in doc:

as the sender or target of a signal handler. Instead, you must register the handler with the resulting User model

juanpex
  • 140
  • 8
1

You can simply use the setting AUTH_USER_MODEL or any model as a string, e.g. 'users.MyCustomUser':

def user_post_save_handler(**kwargs):
    # do something
post_save.connect(user_post_save_handler, sender=settings.AUTH_USER_MODEL)
Tobias Lorenz
  • 1,426
  • 11
  • 17
  • your method is giving error while creating profile AttributeError: 'str' object has no attribute 'objects' – Lord-shiv Aug 06 '21 at 07:21
  • @Lord-shiV Seems you are doing something like `'foo'.objects.whatever()` in your code. Please check your code inside your handler function. – Tobias Lorenz Aug 07 '21 at 08:10