Yuval Adam
Yuval Adam

Reputation: 165232

Authenticating a custom user in Django 1.5

I have a custom user in a Django 1.5 project, which uses the email field as the username:

class MyUser(AbstractUser):
    my_custom_field = models.CharField(max_length=20, blank=True, null=True)

    USERNAME_FIELD = 'email'

MyUser._meta.get_field_by_name('email')[0]._unique = True
MyUser.REQUIRED_FIELDS.remove('email')

If I try to authenticate that user like so:

auth_user = authenticate(username=email, password=password)
login(request, auth_user)

I get this:

Traceback:
File "/Users/user/dev/proj/app/core/views.py" in post
  39.             login(request, auth_user)
File "/Users/user/.virtualenvs/proj/lib/python2.7/site-packages/django/contrib/auth/__init__.py" in login
  92.     request.session[BACKEND_SESSION_KEY] = user.backend
File "/Users/user/.virtualenvs/proj/lib/python2.7/site-packages/django/utils/functional.py" in inner
  203.         return func(self._wrapped, *args)

Exception Type: AttributeError at /signup
Exception Value: 'AnonymousUser' object has no attribute 'backend'

How am I supposed to authenticate a custom user?

Upvotes: 2

Views: 2258

Answers (2)

Yuval Adam
Yuval Adam

Reputation: 165232

My custom model didn't implement create_user() in its apparently-required custom manager.

Here's the full working code:

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

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

        user = self.model(
            email=MyUserManager.normalize_email(email),
        )

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

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


class MyUser(AbstractUser):
    some_custom_field = models.CharField(max_length=20, blank=True, null=True)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'

MyUser._meta.get_field_by_name('email')[0]._unique = True
MyUser.REQUIRED_FIELDS.remove('email')

Django 1.5 "custom user" implementation is an abomination.

Upvotes: 4

kalo
kalo

Reputation: 408

What Django documentation is saying is

If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you can simply subclass django.contrib.auth.models.AbstractUser and add your custom profile fields

So the idea of AbstractUser is to use it only when you need to add a few additional fields to the user model without creating a separate db table like it was pre Django 1.5.

But when you need a different functionality (like using the email as username,which probably means you won't need the username field) the better approach is the extend the AbstractBaseUser class and set all the fields you need there. This way setting the USERNAME_FIELD='email' will work without writing custom create_user() method.

Upvotes: 1

Related Questions