首页 文章

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

提问于
浏览
22

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

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

    USERNAME_FIELD = 'email'

但是当我跑步的时候

python manage.py sql myapp

我收到以下错误:

FieldError:“CustomUser”类中的本地字段“email”与基类“AbstractUser”中类似名称的字段冲突

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

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

现在,就此而言:https://docs.djangoproject.com/en/1.5/topics/db/models/#field-name-hiding-is-not-permitted
can 我是怎么做到的? (其他然后命名字段"user_email"或类似的东西)

4 回答

  • 9

    您可以编辑 CustomUser 以将 email 字段属性更改为 unique=True .

    将其添加到自定义用户类的末尾,如下所示:

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

    请注意,我们正在更改 _unique 而不是 unique ,因为后者是一个简单的 @property .

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

  • 7

    使用官方网站上的示例:

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

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

  • 36

    伊恩,非常感谢你的聪明回应:)

    但是,我已经“修补”了我的解决方案 .

    由于 AbstractUser 也有一个 username 字段,对我来说完全没用
    我决定创建我的"own" AbstractUser .

    通过子类化 AbstractBaseUserPermissionsMixin ,我保留了大多数用户模型内置方法,而不添加任何代码 .

    我还利用这个机会创建了一个自定义 Manager 来消除 username 字段中的所有用法:

    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):
              .....
    

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

    令人遗憾的是,1.5中引入的灵活性与 USERNAME_FIELD 不能用于在所有现有约束下创建灵活的用户模型 .

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

  • 2

    如果您的真实目标是唯一的“电子邮件”值,并忽略“用户名”值,那么您可以:

    • 填写"username",例如 sha256(user.email).hexdigest()[:30]

    • 以这种方式添加唯一性:

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

    这导致:

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

    按预期工作,非常简单 .

相关问题