我想在Django(2.2)中扩展用户模型,并将其与具有特定字段的Host和Guest实体相结合。
在official documentation中,建议使用引用User主键的OneToOne字段创建“Profile”类。
我可以看到3种方法:
解决方案1:Profile,Host和Guest模型:
class Profile(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
language = models.CharField(max_length=2)
class Host(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
host_field= models.CharField(max_length=500)
class Guest(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
guest_field = models.BooleanField(null=False)
解决方案2:主机和来宾模型(配置文件字段重复)
class Host(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
language = models.CharField(max_length=2)
host_field = models.CharField(max_length=500)
class Guest(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
language = models.CharField(max_length=2)
guest_field = models.BooleanField(null=False)
解决方案3:配置文件模型(包含访客和主机字段)
class Profile(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
language = models.CharField(max_length=2)
is_host = models.BooleanField(null=False)
guest_field = models.BooleanField(null=False)
host_field = models.CharField(max_length=500)
所有这些解决方案都有效。
我的问题是:“哪一个是最聪明的,所有事情都考虑在内”(数据库访问越少,编写的代码越少,维护越容易,限制越少等)。
我会提出一个第4种方式,使用带有抽象模型的mixin。这将导出抽象模型的字段到您应用它的字段。这样您就不需要重写代码并仍然将其应用于不同的模型:
class ProfileMixin(models.Model):
k_user = models.OneToOneField(User, on_delete=models.CASCADE)
language = models.CharField(max_length=2)
class Meta:
abstract = True
class Host(ProfileMixin):
host_field = models.CharField(max_length=500)
class Guest(ProfileMixin):
guest_field = models.BooleanField(null=False)
在深入研究Django的doc并阅读解释如何在Django中实现多用户类型的article mentioned by @sam之后,我找到了答案。
它在Django doc中写道:“强烈建议设置自定义用户模型,即使默认的用户模型对您来说已足够”。
以下是我的案例:
class User(AbstractUser):
is_guest = models.BooleanField(default=False)
is_host = models.BooleanField(default=False)
language = models.CharField(max_length=2)
class Host(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
host_field = models.CharField(max_length=500)
class Guest(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
guest_field = models.BooleanField(null=False)
在settings.py中:
AUTH_USER_MODEL = 'path.to.User'
创建新用户时会插入来宾或主持人记录:
user = User.objects.create_user(...)
if is_host:
Host.objects.create(user=user)
else:
Guest.objects.create(user=user)
我很欣赏我可以在请求对象中检测用户“type”(使用request.user.is_host
)。
通过扩展用户类,您还可以使用email
字段进行登录,并使其唯一:
class User(AbstractUser):
[...]
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
如果在生产中您选择在用户模型中添加字段,则可以设置自定义用户模型。
否则你将被困在配置文件中,因此我建议你遵循Django的指导方针并始终扩展用户类,即使你还不需要它。