如何在Django中创建从AbstractUser继承的多个UserProfile?

时间:2019-04-25 13:42:48

标签: python django

原始问题

我想为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)
  • 我将主表和其他3个表设置为互补表。基于此,我基于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)

2 个答案:

答案 0 :(得分:0)

这实际上取决于您要实现的目标,但是最简单的方法将类似于标准is_staff模型中的is_superuserUser字段。

class UserProfile(AbstractUser):
    is_type1_user = models.BooleanField(default=False)
    is_type2_user = models.BooleanField(default=False)
    is_type3_user = models.BooleanField(default=False)

答案 1 :(得分:0)

您可以通过以下方式自定义User模型和UserManager来利用Django's generic relations

首先,您需要导入相关内容:

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