【问题标题】:Django: is extending AbstractBaseUser required to use email as USERNAME_FIELD?Django:扩展 AbstractBaseUser 是否需要将电子邮件用作 USERNAME_FIELD?
【发布时间】:2016-06-02 08:53:05
【问题描述】:

像许多其他人一样,我正在尝试将我的 Django 应用程序配置为使用电子邮件作为用户名字段。我有一些现有的用户帐户已成功迁移到自定义用户模型,尽管现在自定义模型与 Django 用户模型相同:

# accounts/models.py

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
  pass

每当我尝试将USERNAME_FIELD 设置为email 时,都会收到USERNAME_FIELD 不能包含在REQUIRED_FIELDS 中的错误,以及它必须是唯一的错误。 (旁注:基本用户不需要电子邮件,所以我不明白第一个错误)

在继承 AbstractUser 时有没有办法获得这个功能?

或者我只需要继承AbstractBaseUser 并以example 的方式指定每个字段?

如果是后者,我将如何确保我定义与 Django 用户模型完全相同的字段?我不想失去我拥有的用户或导致字段不匹配的问题。

为了使用电子邮件地址作为用户名,必须一路完全指定自定义模型似乎很愚蠢,所以也许我在这里遗漏了一些东西。如果有办法确保 Django User 模型中的唯一字段,我认为这不是问题。

【问题讨论】:

    标签: python django django-custom-user


    【解决方案1】:

    正如Django doc 所说:

    如果您需要的更改纯粹是行为上的,并且不需要对存储在数据库中的内容进行任何更改,则可以创建基于 User 的代理模型。

    因为您想用自定义 User 模型替换它:

    例如,在某些网站上,使用电子邮件地址而不是用户名作为识别令牌更有意义。

    您需要通过子类化AbstractBaseUser 来实现您自己的User 模型。这是一个包含 django 权限的示例代码:

        class User(AbstractBaseUser, PermissionsMixin):
        """
        A class implementing a fully featured User model with admin-compliant
        permissions.
    
        Email and password are required. Other fields are optional.
        """
    
        email = models.EmailField(
            _('Email Address'), unique=True,
            error_messages={
                'unique': _("A user with that email already exists."),
            }
        )
        username = models.CharField(
            _('Username'), max_length=30, unique=True, blank=True, null=True,
            help_text=_('30 characters or fewer. Letters, digits and _ only.'),
            validators=[
                validators.RegexValidator(
                    r'^\w+$',
                    _('Enter a valid username. This value may contain only '
                      'letters, numbers and _ character.'),
                    'invalid'
                ),
            ],
            error_messages={
                'unique': _("The username is already taken."),
            }
        )
        is_staff = models.BooleanField(
            _('Staff Status'), default=False,
            help_text=_('Designates whether the user can log into this admin '
                        'site.')
        )
        is_active = models.BooleanField(
            _('Active'), default=True,
            help_text=_('Designates whether this user should be treated as '
                        'active. Unselect this instead of deleting accounts.')
        )
        date_joined = models.DateTimeField(_('Date Joined'), default=timezone.now)
    
        objects = UserManager()
    
        USERNAME_FIELD = 'email'
    
        class Meta(object):
            verbose_name = _('User')
            verbose_name_plural = _('Users')
            abstract = False
    
        def get_full_name(self):
            """
            Returns email instead of the fullname for the user.
            """
            return email_to_name(self.email)
    
        def get_short_name(self):
            """
            Returns the short name for the user.
            This function works the same as `get_full_name` method.
            It's just included for django built-in user comparability.
            """
            return self.get_full_name()
    
        def __str__(self):
            return self.email
    
        def email_user(self, subject, message, from_email=None, **kwargs):
            """
            Sends an email to this User.
            """
            send_mail(subject, message, from_email, [self.email], **kwargs)
    

    【讨论】:

    • 谢谢 - 因为我有现有用户,我需要通过扩展 AbstractBaseUser 来精确地重新创建现有的 User 模型?我想我有点担心以与源代码相同的定义进行复制(对于 DRY 来说如此)并遇到冲突问题
    • 这最终奏效了——我不得不从复制的 AbstractUser 定义的Meta 中删除abstract=True,但之后就很好了。谢谢!
    • 不客气。我在我的代码中使用了abstract = False。只要您在导入User 类时小心,使用相同的类名不会导致任何问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多