Я занимаюсь разработкой приложения Django в Google Appengine, и я столкнулся с проблемой проектирования БД, где многотабличное наследование представляется наилучшим решением. К сожалению, однако, наследование нескольких таблиц не поддерживается в Appengine, потому что для этого требуются соединения. Я ищу альтернативное решение, которое отвечает следующим требованиям:
** Смотрите обновления внизу **
Существует 3 различных типа пользователя или профиля:
- Бизнес (т.е. владелец)
- Сотрудник
- Клиент
Эти профили имеют определенные атрибуты, но также имеют уникальные атрибуты для своих соответствующих типов. Например, во всех профилях есть контактный адрес электронной почты и номер телефона, но только компании должны предоставлять логотип или указывать свой бизнес.
Кроме того, мне нужно иметь возможность извлекать объекты профиля из БД (независимо от типа) и получать расширенный или дочерний профиль для каждого (бизнес, сотрудник или клиент). Кроме того, объект Business, Employee или Client также должен иметь возможность легкого доступа к родительскому профилю. Другими словами, отношения должны работать в обоих направлениях (например, profile.employee
или employee.profile
).
Пока что я нашел два возможных решения:
OneToOneField в дочерней модели:
class Profile(models.Model):
# Profile may exist before user claims it
user = models.OneToOneField(User, blank=True, null=True)
email ...
phone ...
... other common fields ...
class Business(models.Model):
profile = models.OneToOneField(Profile, verbose_name="user profile", related_name="biz_profile")
class Employee(models.Model):
profile = models.OneToOneField(Profile, verbose_name="user profile", related_name="employee_profile")
class Client(models.Model):
profile = models.OneToOneField(Profile, verbose_name="user profile", related_name="client_profile")
Это позволит мне сделать следующее: profile.biz_profile
и biz.profile
Уникальный общий внешний ключ в родительской модели:
class Profile(models.Model):
content_type=models.ForeignKey(ContentType)
object_id=models.PositiveIntegerField()
content_object=generic.GenericForeignKey('content_type','object_id')
email ...
phone ...
... other common fields ...
class Meta:
unique_together = ('content_type', 'object_id')
class Business(models.Model):
profiles = generic.GenericRelation(Profile)
class Employee(models.Model):
profiles = generic.GenericRelation(Profile)
class Client(models.Model):
profiles = generic.GenericRelation(Profile)
Это позволит мне сделать следующее: profile.content_object
и biz.profiles.all()[0]
Первый подход (OneToOneField) кажется наиболее прямым, но мне нужно было бы придумать лучший способ узнать, какой дочерний элемент вызывать, возможно, установив content_type в модели профиля, создав такой метод:
def get_instance(self):
# Need to look at contenttype framework, but you get the idea
if self.content_type == 'business':
return self.biz_profile
elif self.content_type == 'employee':
return self.employee_profile
elif self.content_type == 'client':
return self.client_profile
return None
Я не настроен ни на одно из этих решений, поэтому я приветствую любые альтернативные решения или улучшения того, что у меня здесь.
Заранее спасибо!
UPDATE
Мои первоначальные требования изменились с тех пор, как я впервые опубликовал. Оказывается, мне нужен только родитель> дочерний доступ НЕ дочерний> родительский. В свете этого я собираюсь использовать уникальный подход «Общий внешний ключ». Однако я все еще ищу ответ на первоначальный вопрос, поэтому не стесняйтесь, если у вас есть решение.