Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.6 AbstractUser not working

Tags:

django

Trying to create my custom user model, this is the code I have:

models.py

class CustomUser(AbstractUser):
    USERNAME_FIELD = 'email'

CustomUser._meta.get_field_by_name('email')[0]._unique=True

settings.py

AUTH_USER_MODEL = 'myapp.CustomUser'

When doing the manage.py syncdb, the following error occurs:

CommandError: One or more models did not validate:
myapp.customuser: The field named as the USERNAME_FIELD should not be included in REQUIRED_FIELDS on a swappable User model.

Can anyone shed some light? Is there a better way of customizing the user model in Django 1.6 without rewriting the entire class extending AbstractBaseUser?

Btw, if I delete USERNAME_FIELD = 'email' from my code and change the core django auth/models.py >> AbstractUser definition, it works. I just can't seem to be able to override the USERNAME_FIELD...

Thanks!

like image 482
Rok Avatar asked Sep 17 '13 15:09

Rok


3 Answers

As made clear by the error message, the reason for is that AbstractUser defines REQUIRED_FIELDS = ['email']. And you cannot set a field in the REQUIRED_FIELDS to be your USERNAME_FIELD. Further detail here.

So if you want email as your primary field the way forward is to extend and redefine the field email on AbstractBaseUser rather than on AbstractUser.

Also this question/answer pair might be relevant to you in case I did not fully grasp your requirements.

like image 89
Joseph Victor Zammit Avatar answered Nov 15 '22 02:11

Joseph Victor Zammit


Josvic, your solution partially resolved my issue. What I had to do in the end was this:

class CustomUser(AbstractUser):

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    def get_username(self):
        return self.email

CustomUser._meta.get_field_by_name('email')[0]._unique=True

This resolved the initial issue that REQUIRED_FIELDS cannot contain the USERNAME_FIELD and as I do not want to redefine the entire User and extend the AbstractBaseUser, I had to include the 'username' in the REQUIRED_FIELD as otherwise the syncdb fails for a different reason (expecting the username for the sake of saving it into the db):

self.UserModel._default_manager.db_manager(database).create_superuser(**user_data)
TypeError: create_superuser() takes exactly 4 arguments (3 given)

Consequently, when doing the syncdb for the first time and having to enter a superuser, the email must be entered twice, as an email as well as a username. It's awkward but it's the cleanest one that I can live with it.

Cheers!

like image 30
Rok Avatar answered Nov 15 '22 03:11

Rok


Josvic hit the nail on the head but I want to provide the solution I used. It's pretty simple.

  1. Remove 'email' or whatever you're using are USERNAME_FIELD from REQUIRE_FIELDS.

  2. In the UserManager that you made, simply write:

    if not email: raise ValueError('Users must have an email address')

This way, you'll manually enforce that an email is required.

This solution is the one that is used here: https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#a-full-example

like image 2
User Avatar answered Nov 15 '22 03:11

User