我想为3种类型的用户创建3个UserProfile。起初,我做了一个CharFiled
作为区分它们的标记,但后来我意识到我必须放一些ForeignKey
来关联这些用户。至于这一步,我不知道如何实现它。
具体来说:
AbstractUser
继承的3种类型的用户,每个用户都可以登录系统AdminstratorA(not a superuser)
AdminstratorB
|--TeacherA
|--TeacherB
|--StudentA
|--StudentB|
以下是我的失败(简化版),使用Django2.1
python3.7
AUTH_USER_MODEL = 'users.UserProfile'
设置一个mysite\settings.py
apps\users\model
from django.contrib.auth.models import AbstractUser
from django.db import models
class AdministratorUser(AbstractUser):
pass
class TeacherUser(AbstractUser):
administrator = models.ForeignKey(AdministratorUser, on_delete=models.CASCADE)
class StudentUser(AbstractUser):
teacher = models.ForeignKey(TeacherUser, on_delete=models.CASCADE)
xadmin
设计了我的管理站点,数据并不代表。我不知道。所以我尝试重新设计我的模型,这是我在顶部描述的计划。apps\users\model
from django.contrib.auth.models import AbstractUser
from django.db import models
class UserProfile(AbstractUser):
user_type_choices = (
('student', 'student'),
('teacher', 'teacher'),
('teacher', 'teacher'),
)
identity = models.CharField(choices=user_type_choices, max_length=100, default='student')
class AdministratorUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
class TeacherUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
administrator = models.ForeignKey(AdministratorUser, on_delete=models.CASCADE)
class StudentUser(models.Model):
user_profile = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
teacher = models.ForeignKey(TeacherUser, on_delete=models.CASCADE)
这实际上取决于你想要实现的目标,但最简单的方法类似于标准is_staff
模型中的is_superuser
和User
字段。
class UserProfile(AbstractUser):
is_type1_user = models.BooleanField(default=False)
is_type2_user = models.BooleanField(default=False)
is_type3_user = models.BooleanField(default=False)
你可以通过以下方式定制Django's generic relations模型以及User
来利用UserManager
:
首先,您需要导入相关的东西:
from django.apps import apps
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.auth.models import AbstractUser, UserManager as OriginalUserManager
UserManager
:
class UserManager(OriginalUserManager):
def _create_user(self, username, email, password, **extra_fields):
"""
Create and save a user with the given username, email, and password.
"""
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
# handle profile creation at user creation
profile_model = User.TYPE_MODELS.get(user.user_type)
profile_model = apps.get_model(app_label='app1', model_name=profile_model)
if profile_model is None:
raise Exception(
"Profile model has not been set in User.TYPE_MODELS for user type {}".format(user.user_type))
profile = profile_model.objects.create()
user.content_type = ContentType.objects.get_for_model(profile_model)
user.object_id = profile.id
user.content_object = profile
user.save(using=self._db)
return user
User
模型:
class User(AbstractUser):
TYPE_1 = 0
TYPE_2 = 1
TYPE_CHOICES = (
(TYPE_1, "Type 1"),
(TYPE_2, "Type 2"),
)
TYPE_MODELS = dict((
(TYPE_1, "ProfileType1"),
(TYPE_2, "ProfileType2"),
))
user_type = models.PositiveSmallIntegerField(choices=TYPE_CHOICES, default=TYPE_1)
# Below the mandatory fields for generic relation
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
objects = UserManager()
class Meta:
unique_together = ('content_type', 'object_id',)
@property
def profile(self):
return self.content_object
然后您可以定义您的配置文件(例如):
class BaseProfileModel(models.Model):
_user = GenericRelation(User)
@property
def user(self):
ctype = ContentType.objects.get_for_model(self.__class__)
try:
event = User.objects.get(content_type__pk=ctype.id, object_id=self.id)
except User.DoesNotExist:
return None
return event
class ProfileType1(BaseProfileModel):
x = models.IntegerField(default=0)
class ProfileType2(BaseProfileModel):
y = models.IntegerField(default=0)
现在您可以使用它们的方式如下:
使用默认用户类型创建用户:
user = User.objects.create_user("someusername")
user.profile --> will yield a ProfileType1 instance
创建具有特定用户类型的用户
user = User.objects.create_user("someothername", user_type=User.TYPE_2)
user.profile --> will yield a ProfileType2 instance
在这两种情况下,如果我们掌握了配置文件实例,我们可以通过以下方式获取用户:
profile.user --> will yield our original user instance