Django - альтернатива многостольному наследованию в Appengine - PullRequest
2 голосов
/ 22 июня 2011

Я занимаюсь разработкой приложения Django в Google Appengine, и я столкнулся с проблемой проектирования БД, где многотабличное наследование представляется наилучшим решением. К сожалению, однако, наследование нескольких таблиц не поддерживается в Appengine, потому что для этого требуются соединения. Я ищу альтернативное решение, которое отвечает следующим требованиям:

** Смотрите обновления внизу **

Существует 3 различных типа пользователя или профиля:

  1. Бизнес (т.е. владелец)
  2. Сотрудник
  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
Мои первоначальные требования изменились с тех пор, как я впервые опубликовал. Оказывается, мне нужен только родитель> дочерний доступ НЕ дочерний> родительский. В свете этого я собираюсь использовать уникальный подход «Общий внешний ключ». Однако я все еще ищу ответ на первоначальный вопрос, поэтому не стесняйтесь, если у вас есть решение.

...