Вы можете использовать общие отношения Django , настроив модель 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