2014-12-01 174 views
0

这是我的代码,是否有更高效的编写方式? 我不喜欢它。Django多个外键模型

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

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) 
+0

不要在CharFields上使用null = True。 – allcaps 2014-12-02 00:08:43

+0

会做@allcaps,谢谢。 – 2014-12-02 18:25:17

回答

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。

这些对底层数据有不同的要求。您现在正在使用三表解决方案(X, Y, C) = (Company, Supplier, Contact)。如果一些联系人将在公司和供应商之间共享,那么这很好,因此有时需要询问“谁是该公司与该供应商之间的联系人”。我维护一个使用双表解决方案的数据库,当它最初被采用时,它是一个很好的解决方案(为什么在我们不需要时重复关于地址和联系人的所有逻辑?),但今天看起来很笨拙(因为“公司”表包含仅对X和Y分别有意义的字段)。

如果我们迁移的话,或许最容易处理的是四表解决方案:保持X型公司的联系人与Y型公司的联系人完全分开。如果你从目前的方法开始,那么如果你的应用程序面临类似的成长的痛苦,五表解决方案将是明显的泛化。

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

  1. 商店一堆联系人表,每一个独立的电话号码列。这真的很难实现,但它是快速简单的方法。这被称为“非规范化”数据。
  2. 将JSON存储在联系人列表中的文本字段中。电话号码不太可能被搜索过多;说“我有这个号码,它属于谁?”并不常见,所以你可以很容易地进行非规范化。这也可以让你做一些事情,如{"mon thru thurs": 12025551234, "fri, sat": 12025554321},为数字存储简单的自定义注释。
  3. 创建一个电话表,就像你现在所做的一样。这是做这件事最常用的方法,如果你需要这些注释,你可以在该表中添加另一个文本字段。

如果你在这里将选项3与上面的选项3混合在一起(四个表加上一个明确的电话表),那么你可能想要有单独的电话表以及单独的联系表; Px和Py每个都有一个外键给Cx和Cy。

+0

很好的答案,谢谢你,我的事情就是这样。但只是为了澄清这里的逻辑。假设我选择了选项3和3,为Cx和Cy留下一个电话表有什么问题?我不明白,即使知道一个电话号码永远不会来自两个不同的联系人。 – 2014-12-01 23:55:57

+0

我猜想有一张桌子是没有什么坏处的,我只是在想它们都在不同的“宇宙”中,所以你不妨将它们分开。另一方面,确实有很多真正的商业应用程序开始涉及如此之多的重复,以至于需要付出巨大的努力才能“将它们粘合在一起”。 – 2014-12-02 15:03:51

+0

这就是我的想法,我试图尽可能保持应用程序的精益。 – 2014-12-02 18:24:56

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) 

这是克里斯Drosts“2台”的解决方案。如果您需要供应商特定字段而不是添加供应商型号,并将其链接到OneToOne的公司:

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

这是一个很好的选择,我喜欢OneToOne解决方案,但就我而言,公司和供应商是完全不同的。所以我更喜欢让他们分开。 – 2014-12-02 00:05:51