我正在 Google Appengine 上开发一个 Django 应用程序,我遇到了一个数据库设计问题,其中多表继承似乎是最好的解决方案。然而不幸的是,Appengine 不支持多表继承,因为它需要 JOIN。我正在寻找满足以下要求的替代解决方案:
** 见底部更新 **
有 3 种不同的用户类型或配置文件:
- 企业(即所有者)
- 员工
- 客户
这些配置文件共享某些属性,但也具有各自类型的独特属性。例如,所有个人资料都有联系电子邮件和电话号码,但只有企业需要提供徽标或指定其业务类型。
此外,我需要能够从数据库中检索 Profile 对象(无论类型如何),并获取每个(业务、员工或客户)的扩展或子配置文件。此外,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)似乎是最直接的,但我需要想出一个更好的方法来知道要调用哪个孩子,也许通过在 Profile 模型中设置 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
我对这些解决方案中的任何一个都没有设置,所以我欢迎任何替代解决方案或改进我在这里的解决方案。
提前致谢!
更新
自从我第一次发布以来,我的原始要求已经改变。事实证明我只需要父>子访问而不是子>父。鉴于此,我将改用独特的通用外键方法。但是,我仍在寻找原始问题的答案,所以如果您有解决方案,请不要害羞。