Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Django Authentication Users and Authorization Custom User Model

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 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

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 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?

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 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).

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 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