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

只愿长相守 提交于 2019-11-28 23:03:50
OrPo

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

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.

You can edit your CustomUser to change the email field attribute to unique=True.

Add this to the end of your custom user class like so:

class CustomUser(AbstractUser):
    ...
    USERNAME_FIELD = 'email'
    ...
CustomUser._meta.get_field_by_name('email')[0]._unique=True

Note that we're changing _unique and not unique because the latter is a simple @property.

This is a hack, and I would love to hear any "official" answers to resolve this.

Use the example from the official site :

https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#a-full-example

Here is an example of an admin-compliant custom user app. This user model uses an email address as the username, and has a required date of birth; it provides no permission checking, beyond a simple admin flag on the user account. This model would be compatible with all the built-in auth forms and views, except for the User creation forms. This example illustrates how most of the components work together, but is not intended to be copied directly into projects for production use.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!