Django多外键模型

时间:2014-12-01 20:12:32

标签: python sql django foreign-keys models

这是我的代码,是否有更有效的编写方式? 我不喜欢它。

基本上,公司和供应商模型都应该能够与多个电话号码联系。

class Contact(models.Model):
    company = models.ForeignKey(Company, related_name='contact',
        blank=True, null=True)
    supplier = models.ForeignKey(Supplier, related_name='contact',
        blank=True, null=True)
    name = models.CharFields(max_length=50, blank=True, null=True)
class Phone(models.Model):
    contact = models.ForeignKey(Contato, related_name='phone')
    number = models.CharFields(max_length=50, blank=True, null=True)

2 个答案:

答案 0 :(得分:1)

至少有四种方法可以解决“X型公司和Y型公司有联系”的问题:

  1. 两个表:公司和联系人。公司的枚举属性具有值X和Y,并且每个联系人都有一个公司的外键。
  2. 三个表:X公司的一个表X,Y公司的另一个表Y,以及联系人C的一个表,其中C具有X和Y的外键。外键可以为空。
  3. 四个表格:X,Y,Cx和Cy,分别跟踪两个不同类型公司的两个不同联系人。 (所以Cx有一个外键到X,而Cy有一个外键到Y)。
  4. 五个表:从这三个表X,Y和C开始,但不是向C添加可空指针,而是添加两个多对多连接表XC和YC。
  5. 这些对基础数据有不同的要求。您现在正在使用三表解决方案(X, Y, C) = (Company, Supplier, Contact)。如果某些联系人将在公司和供应商之间共享,这是很好的,因此您有时需要询问“该公司与该供应商之间的联系人是谁?”。我维护了一个使用双表解决方案的数据库,当它最初被采用时,它是一个很好的解决方案(为什么我们不必重复所有关于地址和联系人的逻辑?)但是今天看起来很笨重(因为“公司”表包含仅对X和Y分别有意义的字段。

    在我的案例中,最容易处理的可能是,如果我们迁移,将是四表解决方案:保持X型公司的联系人与Y型公司的联系人完全分开。如果您从当前的方法开始,那么如果您在应用程序中遇到类似的成长痛苦,那么五表解决方案将是明显的概括。

    至于跟踪电话号码,您有一些有限的选择:

    1. 在“联系人”表格中存储一堆列,每个列分别对应一个电话号码。这变得非常难看,但它是快速简便的方法。这称为“非规范化”数据。
    2. 将JSON存储在“联系人”列表的文本字段中。电话号码不太可能被搜索过多;说“我有这个号码,它属于谁?”并不常见,所以你很容易反规范化。这也允许您执行{"mon thru thurs": 12025551234, "fri, sat": 12025554321}之类的操作,为数字存储简单的自定义注释。
    3. 创建一个电话桌,就像你现在所做的那样。这是执行此操作的最常用方法,如果您需要这些注释,则可以向该表添加另一个文本字段。
    4. 如果你在这里混合选项3和上面的选项3(四个表加上一个明确的电话表),那么你可能希望有单独的电话表以及单独的联系表; Px和Py各有一个Cx和Cy的外键。

答案 1 :(得分:0)

对我来说CompanySupplier模型可能是相同的。既然大多数供应商都是公司吗?如果它们基本上与合并CompanySupplier模型相同:

class Company(models.Model):
    name = models.CharFields(max_length=50)
    is_supplier = models.BooleanField(default=False)  
    suppliers = models.ManyToManyField("self", 
        limit_choices_to={'is_supplier': True})


class Contact(models.Model):
    name = models.CharFields(max_length=50)    
    company = models.ForeignKey(Company)


class Phone(models.Model):
    number = models.CharFields(max_length=50)    
    contact = models.ForeignKey(Contact)

这是Chris Drosts' 2 table'解。如果您需要供应商特定字段而不是添加供应商模型并使用OneToOne将其链接到公司:

class Supplier(models.Model):
    ... # Some supplier specific fields.
    company = models.OneToOneField(Company)