Django - несколько профилей пользователей - PullRequest
24 голосов
/ 11 марта 2012

Изначально я запустил свой 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), а для корпоративных я бы хотел, чтобы у них было несколько пользователей, связанных с одним и тем же профилем, поэтому вместо этого у меня было бы 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, которые все смешаны вместе, и тогда я буду использовать необходимые при необходимости. Но это не выглядит чистым для меня, я бы лучше выделил их и использовал подходящую модель в соответствующем месте.

Любые предложения о чистом способе сделать это?

Ответы [ 3 ]

23 голосов
/ 11 марта 2012

Вы можете сделать это следующим образом. Иметь профиль, который будет содержать общие поля, которые необходимы в обоих профилях. И вы уже сделали это, создав класс 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 %}

Надеюсь, это приведет вас куда-нибудь. Спасибо

7 голосов
/ 17 марта 2012

Я так и сделал.

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.

0 голосов
/ 11 марта 2012

Может быть стоит попробовать использовать сквозное поле.Идея заключается в том, чтобы использовать модель UserProfile как сквозную модель для моделей CorpProfile или IndividualProfile.Таким образом, он создается, как только профиль Corp или Individual связан с пользователем:

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 или IndividualProfile, связанный с реальным пользователем, создает уникальную модель UserProfile.Затем вы можете получить к нему доступ с помощью запросов базы данных или чего угодно.

Я не проверял это, поэтому никаких гарантий.Это может быть немного хакерским, но с другой стороны я нахожу эту идею довольно привлекательной.:)

...