问题
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?
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/16689056/authenticating-a-custom-user-in-django-1-5