为什么修改 AUTH_USER_MODEL 似乎需要子类化 AbstractUser?

Why does modifying AUTH_USER_MODEL seem required to subclass AbstractUser?

在创建了一个项目,然后是一个应用程序并将这个应用程序添加到我的 INSTALLED_APPS 之后,我尝试通过 subclassing AbstractUser 创建一个自定义用户 class在我的 models.py 中:

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass

然后我尝试 运行 makemigrations 我得到了这个错误:

SystemCheckError: System check identified some issues:

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

添加AUTH_USER_MODEL = 'main.CustomUser'main是我的应用程序)似乎解决了这个问题(makemigrations成功,就像migrate一样),但我不明白为什么即使我只是定义了这个子 class 而没有实际使用它 .

我也会收到这个错误

首先想了解为什么会出现这个问题,加上AUTH_USER_MODEL是如何解决的。我真的不明白为什么我的 CustomUserauth.User.

之间看起来有冲突

因为 AbstractUser(或者说它继承自的 PermissionMixin)定义了与其他模型的关系——即组、权限——并且它使用硬编码的 related_name 属性 user_set,以如果模型被换出,避免混淆。

只要 class 保持抽象就可以,但是一旦定义了具体的子 class,Django 就会定义与该模型的反向关系;现在您有两个模型使用相同的值 user_set 作为组中的相关名称。

如果设置AUTH_USER_MODEL,那么Django不再定义标准Userclass;所以你又回到了只有一个 class 使用 related_name.

的情况

您的自定义用户模型继承了 AbstractUser,它是 django.contrib.auth 的模型 class。

AbstractUserAbstractBaseUserPermissionsMixin 模型定义自身,因此通过 PermissionsMixin class

与组和权限模型相关联

PermissionsMixin 定义与 PermissionGroupsManyToManyField 关系(与 Permission 进一步相关的 ManyToMany)模型,例如:

class PermissionsMixin(models.Model):
....

    groups = models.ManyToManyField(
        Group,
        ....
        related_name="user_set",
        related_query_name="user",
    )
    user_permissions = models.ManyToManyField(
        Permission,
        ....
        related_name="user_set",
        related_query_name="user",
    )

PermissionsMixin 使用 PermissionGroup 模型定义 related_name="user_set",因此 AbstractUser 模型与这些模型具有相反的关系。

当您子class AbstractUser 时,您定义了两个与GroupPermission 具有相同related_name 反向关系的模型。

But You can't have two generic or foreign keys with identical related_names pointing to the same model.

You must always specify a unique reverse name and query name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes.

因此您的申请中只能有一个 AbstractUser 的子 class。

如果你 subclass AbstractUser 那么你必须将该子模型指向 AUTH_USER_MODEL,这样你的应用程序就指向一个 AbstractUser 的实例而不是两个。