Django - несколько профилей пользователей
Сначала я начал свой UserProfile следующим образом:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField()
mobile = models.CharField(max_length=32)
def __unicode__(self):
return self.user.email
Что хорошо работает с AUTH_PROFILE_MODULE = 'accounts.UserProfile'
, установленным в settings.py
.
Тем не менее, у меня есть два разных типа пользователей на моем веб-сайте, индивидуальные и корпоративные, каждый из которых имеет свои уникальные атрибуты. Например, я хотел бы, чтобы у моих индивидуальных пользователей был только один пользователь, поэтому он имел user = models.OneToOneField(User)
, а для Corporate я хотел бы, чтобы у них было несколько пользователей, связанных с одним и тем же профилем, поэтому вместо этого я имел бы user = models.ForeignKey(User)
.
Поэтому я подумал о разделении модели на две разные модели: IndivProfile
и CorpProfile
, оба наследуемые от UserProfile
, перемещая атрибуты, специфичные для модели, в соответствующие подмодели. Мне кажется хорошей идеей и, вероятно, будет работать, однако я бы не смог указать AUTH_PROFILE_MODULE
таким образом, так как у меня есть два профиля пользователей, которые бы отличались для разных пользователей.
Я также думал о том, чтобы делать это наоборот, имея UserProfile
наследование от нескольких классов (моделей), примерно так:
class UserProfile(IndivProfile, CorpProfile):
# some field
def __unicode__(self):
return self.user.email
Таким образом, я бы установил AUTH_PROFILE_MODULE = 'accounts.UserProfile'
и решил проблему. Но это не похоже на то, что он будет работать, поскольку наследование в python работает слева направо, и все переменные в IndivProfile
будут доминировать.
Конечно, у меня всегда может быть одна модель с переменными IndivProfile
и CorpProfile
, которые все смешиваются вместе, а затем я буду использовать необходимые, где это необходимо. Но это просто не выглядит чистым для меня, я бы предпочел, чтобы они были разделены и использовали подходящую модель в соответствующем месте.
Любые предложения по чистым образом?
Ответы
Ответ 1
Я сделал это таким образом.
PROFILE_TYPES = (
(u'INDV', 'Individual'),
(u'CORP', 'Corporate'),
)
# used just to define the relation between User and Profile
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey('Profile')
type = models.CharField(choices=PROFILE_TYPES, max_length=16)
# common fields reside here
class Profile(models.Model):
verified = models.BooleanField(default=False)
В итоге я использовал промежуточную таблицу, чтобы отразить связь между двумя абстрактными моделями User
, которая уже определена в Django и моей модели Profile
. В случае наличия несовместимых атрибутов я создам новую модель и свяжу ее с Profile
.
Ответ 2
Вы можете сделать это следующим образом. Имейте профиль, который будет содержать общие поля, которые необходимы в обоих профилях. И вы уже сделали это, создав класс UserProfile
.
class UserProfile(models.Model):
user = models.ForeignKey(User)
#some common fields here, which are shared among both corporate and individual profiles
class CorporateUser(models.Model):
profile = models.ForeignKey(UserProfile)
#corporate fields here
class Meta:
db_table = 'corporate_user'
class IndividualUser(models.Model):
profile = models.ForeignKey(UserProfile)
#Individual user fields here
class Meta:
db_table = 'individual_user'
Здесь нет ракетостроения. Просто укажите ключевое слово, которое будет различать корпоративный профиль или индивидуальный профиль. Например. Учтите, что пользователь регистрируется. Затем введите поле в форме, которое будет отличать, подписывается ли пользователь на корпоративный или нет. И используйте это ключевое слово (параметр запроса), чтобы сохранить пользователя в соответствующей модели.
Затем, когда вы захотите проверить, что профиль пользователя является корпоративным или индивидуальным, вы можете проверить его, написав небольшую функцию.
def is_corporate_profile(profile):
try:
profile.corporate_user
return True
except:
return False
#If there is no corporate profile is associated with main profile then it will raise exception and it means its individual profile
#you can use this function as a template function also to use in template
{%if profile|is_corporate_profile %}
Надеюсь, это приведет вас куда-нибудь.
Благодаря
Ответ 3
Возможно, стоит попробовать использовать сквозное поле. Идея этого заключается в использовании модели UserProfile как модели для моделей CorpProfile или IndivProfile. Таким образом, он создается, как только профиль Corp или Indiv связан с пользователем:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey(Profile, related_name='special_profile')
class Profile(models.Model):
common_property=something
class CorpProfile(Profile):
user=models.ForeignKey(User, through=UserProfile)
corp_property1=someproperty1
corp_property2=someproperty2
class IndivProfile(Profile):
user=models.ForeignKey(User, through=UserProfile, unique=true)
indiv_property1=something
indiv_property2=something
Я думаю, что так должно быть возможно установить AUTH_PROFILE_MODULE = 'accounts.UserProfile'
, и каждый раз, когда вы создаете либо CorpProfile, либо IndivProfile, который связан с реальным пользователем, создается уникальная модель UserProfile. Затем вы можете получить доступ к этому с помощью запросов db или того, что вы хотите.
Я не тестировал это, поэтому никаких гарантий. Это может быть немного взломанным, но с другой стороны я нахожу эту идею весьма привлекательной.:)