108

I'm been using the default user model in django for quite a abit and I realize , if I need to further enhance it , I would have to create my own custom User Model in django 1.5 .

I created my custom user model and I have a function which allows users to sign in . I think my custom user model is incompatible with my function because it wouldn't allow me to do request.user . How can I fix this so I can use request.user again?

views

 def LoginRequest(request):
         form = LoginForm(request.POST or None)    
    if request.user.is_authenticated():
             username = User.objects.get(username=request.user)
             url = reverse('world:Profile', kwargs = {'slug': person.slug})
             return HttpResponseRedirect(url)       
         if request.POST and form.is_valid():

             user = form.authenticate_user()
             login(request, user)
            username= User.objects.get(username=request.user)
                person = Person.objects.get(user=request.user)
            url = reverse('world:Profile', kwargs = {'slug': person.slug})
             return HttpResponseRedirect(url)

    return render(request, 'login.html',{'form': form})

models

 class PersonManager(BaseUserManager):
     def create_user(self, email,date_of_birth, username,password=None,):
         if not email:
             msg = 'Users must have an email address'
             raise ValueError(msg)

         if not username:
              msg = 'This username is not valid'
        raise ValueError(msg)

         if not date_of_birth:
             msg = 'Please Verify Your DOB'
             raise ValueError(msg)

         user = self.model(

 email=PersonManager.normalize_email(email),username=username,date_of_birth=date_of_birth)

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

     def create_superuser(self,email,username,password,date_of_birth):
         user = self.create_user(email,password=password,username=username,date_of_birth=date_of_birth)
         user.is_admin = True
         user.is_staff = True
         user.is_superuser = True
         user.save(using=self._db)
         return user


 class Person(AbstractBaseUser, PermissionsMixin):

     email = models.EmailField(verbose_name='email address',max_length=255,unique=True,db_index=True,)
     username = models.CharField(max_length=255, unique=True)
     date_of_birth = models.DateField()

     USERNAME_FIELD = 'email'
     REQUIRED_FIELDS = ['username', 'date_of_birth',]

     is_active = models.BooleanField(default=True)
     is_admin = models.BooleanField(default=False)
     is_staff = models.BooleanField(default=False)

     objects = PersonManager()

     def get_full_name(self):
         return self.email

     def get_short_name(self):
         return self.email

     def __unicode__(self):
         return self.email
JackRoster
  • 1,603
  • 5
  • 16
  • 23

6 Answers6

217

The problem is that User refers to django.contrib.auth.models.User and now you have got a Custom User pet.Person assuming you have in the settings.py

AUTH_USER_MODEL = "pet.Person"

you have to define User with the Custom User model and you can do this with get_user_model at the top of the file where you use User

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

now you will be able to use Custom User model and the problem has been fixed.

aircraft
  • 25,146
  • 28
  • 91
  • 166
Victor Castillo Torres
  • 10,581
  • 7
  • 40
  • 50
  • Hello, this looks like it will solve my problem - I was wondering which file that code ought to go in? Thanks! – Gershom Maes May 13 '15 at 19:48
  • 6
    @GershomMaes AUTH_USER_MODEL inside settings.py and the other code in your views or wherever you use the User model, You're welcome :D – Victor Castillo Torres May 13 '15 at 22:13
  • Worked, much appreciated! – Gershom Maes May 14 '15 at 15:05
  • 1
    If you're looking for this info in the docs: https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#referencing-the-user-model – gmagno Nov 21 '19 at 13:05
  • 2
    Probably this has nothing with this question, I just want note about same error message. In my case in Django 3.0.4 I have used contrib.auth.forms.UserCreationForm of .UserChangeForm and both they have model=User hardcoded in their Meta class (instead of =UserModel which is in this file equal to get_user_model()). I made PR but I don't know if replacement User->UserModel is correct and there are many PR waiting in Django project. – mirek Mar 29 '20 at 15:35
  • Workaround for previous case (contrib.auth.forms with hardcoded User) is: from django.contrib.auth.forms import UserCreationForm as UCF; from django.contrib.auth.forms import UserModel; class UserCreationForm(UCF): Meta = UCF.Meta; Meta.model=UserModel – mirek Mar 29 '20 at 15:37
  • If you came here having stuck implementing `UserCreationForm` — docs [Custom users and the built-in auth forms](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#custom-users-and-the-built-in-auth-forms) have an answer: "If your custom user model is a subclass of AbstractUser, then you can extend these forms: `class CustomUserCreationForm(UserCreationForm):...` – Denis May 12 '20 at 22:11
  • Note that `from django.contrib.auth import get_user_model User = get_user_model()` need to go in your `backends.py` file if you're using a custom auth backend. Took me a while to figure that out. – Evan May 22 '20 at 17:24
  • @VictorCastilloTorres is "file where you use `User`" to say to *re*redefine `User`? Like this: ```from my_app.models import User from django.contrib.auth import get_user_model User = get_user_model()``` – John Jul 03 '23 at 16:48
15

For anyone else who might come across this problem, I also solved it by simply doing this on forms.py:

add this at the top of the forms.py file

from .models import YourCustomUser

and then add this to your forms.py CustomUser form:

class SignUpForm(UserCreationForm):
#profile_year        = blaaa blaa blaaa irrelevant.. You have your own stuff here don't worry about it

   # here is the important part.. add a class Meta-
   class Meta:
      model = YourCustomUser #this is the "YourCustomUser" that you imported at the top of the file  
      fields = ('username', 'password1', 'password2', #etc etc, other fields you want displayed on the form)

BIG NOTES, ATTENTION:

  1. This code worked for my case. I have a view for signing users up, I had a problem here and I solved it, I haven't tried it for logging in users.

  2. The include = () part is required, or you can add exclude = (), but you have to have one

zx485
  • 28,498
  • 28
  • 50
  • 59
justbecause
  • 189
  • 2
  • 9
  • 3
    **Warning**: The [docs](https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#referencing-the-user-model) state that you should use `settings.AUTH_USER_MODEL` or `get_user_model()` instead of this method. I'm not sure if this is only a convention, or if there are security concerns. – Lord Elrond Oct 09 '19 at 18:42
12

Important caveat to update the above 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 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...

J-a-n-u-s
  • 1,469
  • 17
  • 20
8

In forms.py

# change
from django.contrib.auth.models import User

# to
from django.contrib.auth import get_user_model

Then add the following code at the top

User = get_user_model()
John Doe
  • 111
  • 2
  • 14
Owen Murithi
  • 81
  • 1
  • 1
  • How do I also get group model ? `ImportError: cannot import name 'get_group_model' from 'django.contrib.auth'` – anjanesh Mar 23 '23 at 08:32
0

In my case, the issue was due to the way my app's forms.py was set up.

I found the cause of the error, and added it. See comment in code:

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model


class RegisterForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = get_user_model() #### I included this,VERY IMPORTANT
        fields = ("email",)

It was missing initially, hence the reason for the error.

If you've noticed, my class RegisterForm extends UserCreationForm

And UserCreation extends a Base class, BaseUserCreationForm

BaseUserCreationForm in turn has a Meta subclass with a model = User.

By default, that models points to django.contrib.auth.models.User

which is not something you want, since you're already using a custom class.

Mona
  • 31
  • 3
-4

All the solutions provided above did not work in my case. If you using Django version 3.1 there is another solution for you:

In auth/forms, comment out line 10 and change the model in line 104 & 153 to your defined model.

M--
  • 25,431
  • 8
  • 61
  • 93