Python Django Authentication Users and Authorization Custom User Model

Alexey Kislitsin
Alexey Kislitsin
Python Web Development Techdegree Graduate 14,808 Points

My automatic login stopped working after adding custom User.

Hi, Kenneth Love !

I added some code to SignUp view to login users automatically right after signing up.

class SignUp(generic.CreateView):
    form_class = forms.UserCreationForm
    success_url = reverse_lazy('posts:all')
    template_name = "accounts/signup.html"

    def form_valid(self, form):  
        valid = super().form_valid(form)
        username, password = form.cleaned_data.get('username'), form.cleaned_data.get('password1')
        user = authenticate(username=username, password=password)  # This returns None
        login(self.request, user)
        return valid

It worked well. But.

After we added a custom User model, when I Sign Up a new user it creates new user and then returns 500 error on this line:

login(self.request, user)

Here is an error:

request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
AttributeError: 'AnonymousUser' object has no attribute '_meta'
"POST /accounts/signup/ HTTP/1.1" 500 97428

What would be the way to solve it?

UPDATE: For some reason this line from form_valid(self, form) doesn't work any more:

user = authenticate(username=username, password=password)  # This returns None

2 Answers

Alexey Kislitsin
Alexey Kislitsin
Python Web Development Techdegree Graduate 14,808 Points

Here it is:

from django.contrib.auth.models import (
    AbstractBaseUser,
    BaseUserManager,
    PermissionsMixin
)
from django.db import models
from django.utils import timezone

# Create your models here.


class UserManager(BaseUserManager):
    def create_user(self, email, username, display_name=None, password=None):
        if not email:
            raise ValueError("Users must have an email address!")
        if not display_name:
            display_name = username

        user = self.model(
            email=self.normalize_email(email),
            username=username,
            display_name=display_name
        )

        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, username, display_name, password):
        user = self.create_user(email, username, display_name, password)
        user.is_staff = True
        user.is_superuser = True
        user.save()
        return user


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    username = models.CharField(max_length=40, unique=True)
    display_name = models.CharField(max_length=140)
    bio = models.CharField(max_length=140, blank=True, default="")
    avatar = models.ImageField(blank=True, null=True)
    date_joined = models.DateTimeField(default=timezone.now)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["display_name", "username"]

    def __str__(self):
        return "@{}".format(self.username)

    def get_short_name(self):
        return self.display_name

    def get_full_name(self):
        return "{} (@{})".format(self.display_name, self.username)
Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

Hmm, I don't see anything that looks off. You've set AUTH_USER_MODEL in settings.py, yeah?

Alexey Kislitsin
Alexey Kislitsin
Python Web Development Techdegree Graduate 14,808 Points

Yes, sure. It creates user in database correctly. Newly created user is active, and can log in with LoginView.

Maybe authenticate() expects email and password?

Kenneth Love
Kenneth Love
Treehouse Guest Teacher

Ah, yeah, you should be doing, effectively authenticate(username=form.email, password=form.password1) (fake code, but you get what I mean).

Alexey Kislitsin
Alexey Kislitsin
Python Web Development Techdegree Graduate 14,808 Points

Works with:

    def form_valid(self, form):  
        valid = super().form_valid(form)
        email, password = form.cleaned_data.get('email'), form.cleaned_data.get('password1')
        user = authenticate(email=email, password=password)
        login(self.request, user)
        return valid