Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set email as username in Django 1.5

Tags:

python

django

I am reading the docs at: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#substituting-a-custom-user-model

So in my settings.py I put:

AUTH_USER_MODEL = 'membership.User'

And in my membership app models.py I have this:

from django.contrib.auth.models import AbstractBaseUser

class User(AbstractBaseUser):
    USERNAME_FIELD = 'email'

Running python manage.py syncdb is giving me:

FieldDoesNotExist: User has no field named 'email'

I check AbstractBaseUser class source and the field is defined of course, as you can see here: https://github.com/django/django/blob/master/django/contrib/auth/models.py#L359

What's wrong?

like image 937
Adam Silver Avatar asked May 19 '13 19:05

Adam Silver


1 Answers

AbstractBaseUser doesn't have email field, the AbstractUser does.

If you want to use email as a unique identifier, then you need to subclass from AbstractBaseUser and define email field with unique=True and also write other functionality, for example Manager of the model:

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager,\
    PermissionsMixin
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.utils.http import urlquote


class CustomUserManager(BaseUserManager):

    def create_user(self, email, password=None, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        now = timezone.now()
        if not email:
            raise ValueError('The given email must be set')
        email = CustomUserManager.normalize_email(email)
        user = self.model(email=email,
                          is_staff=False, is_active=True, is_superuser=False,
                          last_login=now, date_joined=now, **extra_fields)

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

    def create_superuser(self, email, password, **extra_fields):
        u = self.create_user(email, password, **extra_fields)
        u.is_staff = True
        u.is_active = True
        u.is_superuser = True
        u.save(using=self._db)
        return u


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    is_staff = models.BooleanField(_('staff status'), default=False,
        help_text=_('Designates whether the user can log into this admin '
                    'site.'))
    is_active = models.BooleanField(_('active'), default=True,
        help_text=_('Designates whether this user should be treated as '
                    'active. Unselect this instead of deleting accounts.'))
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = CustomUserManager()

    USERNAME_FIELD = 'email'

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

    def get_absolute_url(self):
        return "/users/%s/" % urlquote(self.pk)

    def get_full_name(self):
        """
        Returns the first_name plus the last_name, with a space in between.
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        "Returns the short name for the user."
        return self.first_name

    # define here other needed methods
    # Look at django.contrib.auth.models.AbstractUser

Also, you'll probably want to add this user to admin page. Look at UserAdmin and redefine it to be compatible with new user model, that use email field as unique identifier.

like image 84
stalk Avatar answered Sep 22 '22 10:09

stalk