Search code examples
pythondjangodjango-modelsdjango-authenticationdjango-auth-models

Django custom user error when registering: get_session_auth_hash() missing 1 required positional argument: 'self' (new user can otherwise log in)


I am aware of this answer: TypeError: get_session_auth_hash() missing 1 required positional argument: 'self', but I am not using a custom backend and the error in question happens when registering a new user through a Django form, not when logging in.

Further, whilst the user does not remain logged in when registering and is not automatically redirected to the main page as intended, logging in from the log in form seems to function normally.

The error happens on this line in my registration view: login(request, User)

And traces back to this line in django.contrib.auth:

    if user is None:
        user = request.user
    if hasattr(user, 'get_session_auth_hash'):
        session_auth_hash = user.get_session_auth_hash() <<<<<<<<< This line

I think because I'm using a custom user, there's something else I need to modify in the default code, but I'm not sure what this should be. I think the custom user model should be interchangeable with the default user model, but it isn't and I'd welcome someone with more experience than me pointing me in the right direction.

My code as follows:

Custom user model and manager in models.py:

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

class UserManager(BaseUserManager):
    def create_user(self, email, password = None, active = True, staff = False, superuser = False):
        if not email:
            raise ValueError('Users must have an email')
        if not password:
            raise ValueError('Users must have a password')
        user = self.model(email = self.normalize_email(email))
        user.set_password(password)
        user.staff = staff
        user.superuser = superuser      
        user.active = active     
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, password = None):
        user = self.create_user(email, password = password, staff = True)
        return user

    def create_superuser(self, email, password = None):
        user = self.create_user(email, password = password, staff = True, superuser = True)
        return user

class User(AbstractBaseUser):
    user_id         = models.AutoField(primary_key=True)
    email           = models.EmailField(max_length = 255, unique =True, default = 'abc123@domain.ext')
    active          = models.BooleanField(default = True)#can login
    staff           = models.BooleanField(default = False)#staff user non superuser
    superuser       = models.BooleanField(default = False)#superuser
    
    USERNAME_FIELD = 'email' #to set username
    #username and passwor fields are required by default
    REQUIRED_FIELDS = []

    objects = UserManager()

    def __str__(self):
        return (str(self.user_id) + ' ' + ' ' + self.email)

    def has_perm(self, perm, obj=None):
        return self.superuser

    def has_module_perms(self, app_label):
        return self.superuser

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_superuser(self):
        return self.superuser
    

    @property
    def is_active(self):
        return self.active

Registration view in views.py:

from .models import User
from .forms import NewUserForm

def register_request(request):
    if request.method == "POST":
        form = NewUserForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, User)
            messages.success(request, "Registration successful." )
            return redirect("main:homepage")
        messages.error(request, "Unsuccessful registration. Invalid information.")
    form = NewUserForm()
    return render (request=request, template_name="main/register.html", context={"register_form":form})

forms.py

from django.contrib.auth.forms import UserCreationForm
from .models import User

class NewUserForm(UserCreationForm):
    email = forms.EmailField(required=True)

    class Meta:
        model = User
        fields = ("email", "password1", "password2")

    def save(self, commit=True):
        user = super(NewUserForm, self).save(commit=False)
        user.email = self.cleaned_data['email']
        if commit:
            user.save()
        return user

Please tell me if there's anything else you need to see. Please forgive me if this question is answered elsewhere here, but I have looked, and not just at the link above! Thanks in advance.

Note: Tried replacing

from .models import User

with:

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

in all modules which utilises User model. Same error occurs at same locations.


Solution

  • You've got a typo in login. You are using User which is the class instead of user:

    login(request, User) # --> should be login(request, user)