在Django 1.5自定义用户模型中使用电子邮件作为用户名字段导致FieldError

时间:2022-06-07 19:24:19

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:

我想使用电子邮件字段作为我的自定义用户模型的用户名字段。我有以下自定义用户模型子类化Django的AbstractUser模型:

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

    USERNAME_FIELD = 'email'

But when I run

但是当我跑步的时候

python manage.py sql myapp

python manage.py sql myapp

I get the following error:

我收到以下错误:

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

FieldError:类'CustomUser'中的本地字段'email'与基类'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:

我首先包含自己的电子邮件字段的原因是为它添加unique = True选项。否则我得到:

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

myapp.customuser:USERNAME_FIELD必须是唯一的。将unique = True添加到字段参数中。

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)

现在,就此而言:https://docs.djangoproject.com/en/1.5/topics/db/models/#field-name-hiding-is-not-permitted我该如何实现这一目标? (另外,然后命名字段“user_email”或类似的东西)

4 个解决方案

#1


34  

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.

由于AbstractUser也有一个用户名字段,对我来说完全没用,我决定创建我自己的“AbstractUser”。

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

通过继承AbstractBaseUser和PermissionsMixin,我保留了大多数User模型内置方法而不添加任何代码。

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.

这个解决方案确实导致重复一些Django的内置代码(主要是AbstractUser中已经存在的模型字段,如'first_name','last_name'等),但也在一个更干净的User对象和数据库表中。

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.

使用USERNAME_FIELD在1.5中引入的灵活性不能用于在所有现有约束下实际创建灵活的用户模型,这真是一种耻辱。

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

编辑:官方文档中提供了一个全面的工作示例:https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example

#2


8  

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]
  • 填写“用户名”,例如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.

按预期工作,非常简单。

#3


7  

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

您可以编辑CustomUser以将email字段属性更改为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.

请注意,我们正在改变_unique并且不是唯一的,因为后者是一个简单的@property。

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

这是一个黑客,我很想听到任何“官方”的答案来解决这个问题。

#4


2  

Use the example from the official site :

使用官方网站上的示例:

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

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.

以下是符合管理员的自定义用户应用的示例。此用户模型使用电子邮件地址作为用户名,并具有所需的出生日期;除了用户帐户上的简单管理标志之外,它不提供权限检查。除用户创建表单外,此模型将与所有内置身份验证表单和视图兼容。此示例说明了大多数组件如何协同工作,但不打算直接复制到项目中以供生产使用。

#1


34  

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.

由于AbstractUser也有一个用户名字段,对我来说完全没用,我决定创建我自己的“AbstractUser”。

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

通过继承AbstractBaseUser和PermissionsMixin,我保留了大多数User模型内置方法而不添加任何代码。

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.

这个解决方案确实导致重复一些Django的内置代码(主要是AbstractUser中已经存在的模型字段,如'first_name','last_name'等),但也在一个更干净的User对象和数据库表中。

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.

使用USERNAME_FIELD在1.5中引入的灵活性不能用于在所有现有约束下实际创建灵活的用户模型,这真是一种耻辱。

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

编辑:官方文档中提供了一个全面的工作示例:https://docs.djangoproject.com/en/dev/topics/auth/customizing/#a-full-example

#2


8  

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]
  • 填写“用户名”,例如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.

按预期工作,非常简单。

#3


7  

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

您可以编辑CustomUser以将email字段属性更改为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.

请注意,我们正在改变_unique并且不是唯一的,因为后者是一个简单的@property。

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

这是一个黑客,我很想听到任何“官方”的答案来解决这个问题。

#4


2  

Use the example from the official site :

使用官方网站上的示例:

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

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.

以下是符合管理员的自定义用户应用的示例。此用户模型使用电子邮件地址作为用户名,并具有所需的出生日期;除了用户帐户上的简单管理标志之外,它不提供权限检查。除用户创建表单外,此模型将与所有内置身份验证表单和视图兼容。此示例说明了大多数组件如何协同工作,但不打算直接复制到项目中以供生产使用。