为什么修改 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
是如何解决的。我真的不明白为什么我的 CustomUser
和 auth.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。
AbstractUser
从 AbstractBaseUser
和 PermissionsMixin
模型定义自身,因此通过 PermissionsMixin class
与组和权限模型相关联
PermissionsMixin
定义与 Permission
和 Groups
的 ManyToManyField
关系(与 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
使用 Permission
和 Group
模型定义 related_name="user_set"
,因此 AbstractUser
模型与这些模型具有相反的关系。
当您子class AbstractUser
时,您定义了两个与Group
和Permission
具有相同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 的实例而不是两个。
在创建了一个项目,然后是一个应用程序并将这个应用程序添加到我的 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
是如何解决的。我真的不明白为什么我的 CustomUser
和 auth.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。
AbstractUser
从 AbstractBaseUser
和 PermissionsMixin
模型定义自身,因此通过 PermissionsMixin class
PermissionsMixin
定义与 Permission
和 Groups
的 ManyToManyField
关系(与 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
使用 Permission
和 Group
模型定义 related_name="user_set"
,因此 AbstractUser
模型与这些模型具有相反的关系。
当您子class AbstractUser
时,您定义了两个与Group
和Permission
具有相同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 的实例而不是两个。