Django custom user model and usermanager
Asked Answered
D

5

9

i'm building a web application with Django 1.5. I'm using a custom User model with a custom UserManager. I followed the instructions and examples of the official Django documentation.

Now, when i'm trying to create a new user via UserManager.create_user(...) i'm getting a NoneType error: It seems the UserManager's attribute models is of type None. I think i'm setting up the UserManager correctly in the User model ( objects = UserManager() )

I really don't know where i'm making a mistake. Booth my coding partners and i are new to Django. Maybe you can help us out.

Here is the code:

class UserManager(BaseUserManager):
"""
    create a new user

    @param username:  the name for the new user
    @param password:  the password for the new user. if none is provided a random password is generated
    @param person:    the corresponding person object for this user
"""
def create_user(self, username, person, password=None):
    if not username:
        raise ValueError('User must have a valid username')

    user = self.model(username=username, created=datetime.now(), must_change_password=True, deleted=False, person=person)

    user.set_password(password)
    user.save(using=self._db)
    return user

class User(AbstractBaseUser):
    ## the id of the user. unique through the application
    user_id     =   models.AutoField(primary_key=True)
    ## the name of the user. unique through the application
    username    =   models.CharField(max_length=32, unique=True)
    ## the date when the user was created
    created     =   models.DateTimeField()
    ## iff this is true the user must set a new password at next login
    must_change_password    =   models.BooleanField(default=True)
    ## iff true the user is marked as deleted and can not login
    deleted     =   models.BooleanField(default=False)
    ## iff true the user is admin and has all permissions. use with care!
    is_admin = models.BooleanField(default=False)
    ## reference to the person entity that is linked to this specific user
    person      =   models.ForeignKey(Person)
    ## indicates if the user is active or not
    active    =    models.BooleanField(default=True)

    ## define the user manager class for User
    objects     =   UserManager()

    # necessary to use the django authentication framework: this field is used as username
    USERNAME_FIELD  =   'username'

I'm getting the NoneType Error at line user = self.model(..) in the create_user() method in the UserManager

Dwan answered 17/5, 2013 at 9:59 Comment(0)
A
10

To create new user you shouldn't call UserManager.create_user(...). Instead you should use :

from django.contrib.auth import get_user_model
get_user_model().objects.create_user(...)

This is how django managers work. You can read docs here

Averyaveryl answered 17/5, 2013 at 10:8 Comment(0)
P
9

I also had problems saving the custom user model and it took me while to figure it our

I think the important line in your code is:

objects     =   UserManager()

within the User class, so in order to save the new user you need to call

new_user=User.objects.create_user(args, args, args, etc)

the "objects" is the item that calls the UserManager class and is called a manager in django

Proprioceptor answered 19/5, 2014 at 18:44 Comment(1)
Explain please why this method is bad who downvote the answer.Neurocoele
C
2

I had to add an answer as I don't have enough rep to comment. But the link in @Aldarund's answer does not describe the use of get_user_model() at all. However, this link should help...

Contumacious answered 27/9, 2013 at 7:29 Comment(0)
L
2

Important caveat to update the solutions... If you're facing this kind of problem, you've probably tried various solutions around the web telling you to add AUTH_USER_MODEL = users.CustomUser to settings.py and then to add the following code to views.py forms.py and any other file that calls User:

from django.contrib.auth import get_user_model
User = get_user_model()

And then you scratch your head when you get the error:

Manager isn't available; 'auth.User' has been swapped for 'users.User'

Anytime your code references User such as:

User.objects.get()

Cause you know you already put objects = UserManager() in your custom user class (UserManager being the name of your custom manager that extends BaseUserManager).

Well as it turns out (thank you to @Aldarund) doing:

User = get_user_model() # somewhere at the top of your .py file
# followed by
User.objects.get() # in a function/method of that same file

Is NOT equivalent to:

get_user_model().objects.get() # without the need for User = get_user_model() anywhere

Perhaps not intuitive, but it turns out that that in python, executing User = get_user_model() once at the time of import does not then result in User being defined across subsequent calls (i.e. it does not turn User into a "constant" of sorts which you might expect if you're coming from a C/C++ background; meaning that the execution of User = get_user_model() occurs at the time of imports, but is then de-referenced before subsequent called to class or function/method in that file).

So to sum up, in all files that reference the User class (e.g. calling functions or variables such as User.objects.get() User.objects.all() User.DoesNotExist etc...):

# Add the following import line
from django.contrib.auth import get_user_model

# Replace all references to User with get_user_model() such as...
user = get_user_model().objects.get(pk=uid)
# instead of  user = User.objects.get(pk=uid)
# or
queryset = get_user_model().objects.all()
# instead of queryset = User.objects.all()
# etc...

Hope this helps save others some time...

Lowe answered 19/6, 2019 at 15:17 Comment(0)
S
0

In my case if you got "manager_method" missing 1 required positional argument: 'self' django err you should notice that unlike model.Manager the UserManager need to set as blow

from django.contrib.auth.models import AbstractUser, UserManager
from django.db.models import Q

class CostumUserManager(UserManager ):
    
    def authors(self):
        return self.filter(Q(is_author=True) | Q(is_superuser=True))


class User(AbstractUser):
    is_author = models.BooleanField(default=False, )


    objects = CostumUserManager() # Use () in end of it

Soutane answered 27/2, 2022 at 21:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.