Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using email as username field in Django 1.5 custom User model results in FieldError

Tags:

I want to use an email field as the username field for my custom user model. I have the following custom User model subclassing Django's AbstractUser model:

class CustomUser(AbstractUser):     ....     email = models.EmailField(max_length=255, unique=True)      USERNAME_FIELD = 'email' 

But when I run

python manage.py sql myapp

I get the following error:

FieldError: Local field 'email' in class 'CustomUser' clashes with field of similar name from base class 'AbstractUser'

The reason I include my own email field in the first place is to add the unique=True option to it. otherwise I get:

myapp.customuser: The USERNAME_FIELD must be unique. Add unique=True to the field parameters.

Now, in respect to this: https://docs.djangoproject.com/en/1.5/topics/db/models/#field-name-hiding-is-not-permitted
How can I achieve this? (other then naming the field "user_email" or something like that instead)

like image 591
OrPo Avatar asked Mar 24 '13 10:03

OrPo


People also ask

Is username unique in Django user model?

If you want to use django's default authentication backend you cannot make username non unique. You will have to implement a class with get_user(user_id) and authenticate(request, **credentials) methods for a custom backend.

What is username field in Django?

For Django's default user model, the user identifier is the username, for custom user models it is the field specified by USERNAME_FIELD (see Customizing Users and authentication). It also handles the default permissions model as defined for User and PermissionsMixin .

Should you create custom user model in Django?

It's highly recommended to set up a custom User model when starting a new Django project. Without it, you will need to create another model (like UserProfile ) and link it to the Django User model with a OneToOneField if you want to add new fields to the User model.


2 Answers

Ian, thank you very much for the clever response :)

However, I've already "patched" me a solution.

Since AbstractUser also have a username field which is totaly unnecessary for me
I decided to create my "own" AbstractUser.

By subclassing AbstractBaseUser and PermissionsMixin I retain most of the User model built-in methods without adding any code.

I also took advantage of that opportunity to create a custom Manager to eliminate the use in username field all together:

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager  class CustomUser(AbstractBaseUser, PermissionsMixin):      ....      email = models.EmailField(max_length=255, unique=True)      first_name = ...      last_name = ...      is_active = ...      is_staff = ...      ....       objects = CustomUserManager()       USERNAME_FIELD = 'email'   class CustomUserManager(BaseUserManager):      def create_user(self, email, password=None, **extra_fields):           .....       def create_superuser(self, email, password, **extra_fields):           ..... 

This solution does result in repetition of some of Django's built-in code (mainly model fields that already exist in AbstractUser such as 'first_name', 'last_name' etc.) but also in a cleaner User object and database table.

It is a real shame that the flexibily introduced in 1.5 with USERNAME_FIELD can not be used to actualy create a flexible User model under all existing constrains.

EDIT: There is a comprehensive worked example available in the official docs: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example

like image 173
OrPo Avatar answered Oct 07 '22 03:10

OrPo


If your real target is unique "email" values, and ignoring "username" values, then you may:

  • Fill "username" with e.g. sha256(user.email).hexdigest()[:30]
  • Add uniqueness this way:

    class User(AbstractUser):     class Meta:         unique_together = ('email', ) 

This results in:

CREATE TABLE "myapp_user" (     ...     "email" varchar(75) NOT NULL,     UNIQUE ("email") ) 

works just as expected, and is pretty simple.

like image 24
Denis Ryzhkov Avatar answered Oct 07 '22 04:10

Denis Ryzhkov