Python - 在 Django 2 中创建多种用户类型和电子邮件作为用户名字段

标签 python django python-3.x django-models django-2.0

我正在使用 Python(3.7) 和 Django(2.2) 开发一个项目,其中我必须实现多种类型的用户:

  1. 个人帐户 - 18 岁以下
  2. 个人帐户 - 18 岁以上
  3. 家长帐户
  4. 教练帐户
  5. 管理员

除此之外,我还需要使用电子邮件作为登录/身份验证的用户名字段。

我尝试使用的策略是构建一个自定义基本模型作为从AbstractBaseUser继承的User,并创建了一个自定义用户管理器 > 将电子邮件设为用户名,但它不起作用。

这是我的完整模型代码:

class UserManager(BaseUserManager):

    def _create_user(self, email, password, is_staff, is_superuser, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')
        now = timezone.now()
        email = self.normalize_email(email)
        user = self.model(
            email=email,
            is_staff=is_staff,
            is_active=True,
            is_superuser=is_superuser,
            last_login=now,
            date_joined=now,
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email=None, password=None, **extra_fields):
        return self._create_user(email, password, False, False, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        user = self._create_user(email, password, True, True, **extra_fields)
        user.save(using=self._db)
        return user


def generate_cid():
    customer_number = "".join([random.choice(string.digits) for i in range(10)])
    return customer_number


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=255, unique=True)
    is_personal_above_18 = models.BooleanField(default=False)
    is_personal_below_18 = models.BooleanField(default=False)
    is_parent = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'email'
    EMAIL_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    def get_absolute_url(self):
        return "/users/%i/" % self.pk

    def get_email(self):
        return self.email


class PersonalAccountAbove18(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE,
                                primary_key=True, related_name='profile')
    customer_id = models.BigIntegerField(default=generate_cid)


class PersonalAccountBelow18(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE,
                                primary_key=True, related_name='profile')
    customer_id = models.BigIntegerField(blank=False)


class ParentAccount(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE,
                                primary_key=True, related_name='profile')
    customer_id = models.BigIntegerField(default=generate_cid)

我对我的方法感到困惑,甚至当我运行 makemigrations 时它也会返回错误:

users.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'. HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.

Update: I removed the PermissionMixin and related_name attributes from child models and migrations are running now but it still require the username instead of email.

最佳答案

makemigrations 中的错误以及后来的错误(在删除 PermissionsMixin 后),需要 username 而不是 email 进行身份验证提示您尚未将自定义模型设置为 Django auth 应用程序使用的默认用户模型。因此,Django 使用 auth.User 模型作为默认用户模型,并且您的模型会像任何其他模型一样添加到项目中。因此,这两种用户模型同时存在,auth.User 是用于身份验证目的的默认/事件模型。

本质上,编辑您的 settings.py 以添加以下内容:

AUTH_USER_MODEL = '<your_app>.User'

现在 Django 将使用您自定义的 User 模型,而不是来自 auth 应用程序的模型(默认),并且 auth.User 模型将被丢弃。 auth 应用使用 get_user_model (django.contrib.auth.get_user_model) 函数获取项目当前事件的用户模型,该模型检查settings.AUTH_USER_MODEL,默认情况下,系统的其余部分(例如admin应用程序)也会检查此设置以获取当前的用户模型。因此,只要您使用 auth 应用程序,上述内容就足够了。

关于Python - 在 Django 2 中创建多种用户类型和电子邮件作为用户名字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59069679/

相关文章:

python - 将其中一个索引作为元组的 MultiIndex

Python - 使用 virtualenv 手动安装包

python - 使用 python 编写文本文件

python 3 : get resource from https server with client certificate authentication

python - win32gui.FindWindow 找不到窗口

django - chromedriver.quit()之后的多个Chrome处理

没有必填字段的 Django 表单

python - 使用 Django EmailMessage 将文本设置为粗体和垂直空间

python - 类函数输出正确但方法错误

linux - 我正在尝试使用子进程模块来运行由 html 文件组成的终端命令