简体   繁体   English

Django多重外键模型

[英]Django Multiple Foreign Key Model

Here is my code, is there a more efficient way of writing it? 这是我的代码,有没有更有效的编写方法? I'm not cool with it. 我不喜欢它。

Basically, both Company and Supplier models should be abble to have several contacts with several phone numbers. 基本上,公司模型和供应商模型都应该具有多个联系人和多个电话号码。

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)

There are at least four approaches to the "both companies of type X and companies of type Y have contacts" problem: 解决“ X型公司和Y型公司都有联系”问题的方法至少有四种:

  1. Two tables: Companies and Contacts. 两个表:公司和联系人。 There is an enumerated property on Companies which has values X and Y, and every contact has one foreign key to a company. 公司有一个枚举的属性,其值为X和Y,并且每个联系人都有一个公司的外键。
  2. Three tables: one table X for X-companies, another table Y for Y-companies, and one table for contacts C, where C has foreign keys to both X and Y. The foreign keys can be nullable. 三个表:一个用于X公司的表X,一个用于Y公司的表Y,以及用于联系人C的一个表,其中C具有指向X和Y的外键。外键可以为空。
  3. Four tables: X, Y, Cx, and Cy, tracking the two different contacts for the two different sorts of companies separately. 四个表:X,Y,Cx和Cy,分别跟踪两种不同类型公司的两种不同联系人。 (So Cx has a foreign key to X, and Cy has a foreign key to Y). (因此,Cx具有X的外键,而Cy具有Y的外键)。
  4. Five tables: you start with these three tables X, Y, and C, but instead of adding nullable pointers to C you add two many-to-many joining tables XC and YC. 五个表:您从这三个表X,Y和C开始,但是没有添加指向C的可空指针,而是添加了两个多对多联接表XC和YC。

These have different demands of the underlying data. 这些对基础数据有不同的要求。 You are right now using the three-table solution (X, Y, C) = (Company, Supplier, Contact) . 您现在正在使用三表解决方案(X, Y, C) = (Company, Supplier, Contact) This is great if some contacts will be shared between companies and suppliers, so that you sometimes need to ask "who's the contact who sits between this company and that supplier?". 如果要在公司和供应商之间共享某些联系,这很好,那么您有时需要问“谁是该公司与该供应商之间的联系人?”。 I maintain a database where the two-table solution is used, and when it was initially adopted it was a good solution (why duplicate all of that logic about addresses and contacts when we don't have to?) but today it seems clunky (because the "Company" table contains fields which only make sense for X's and Y's separately). 我维护着一个使用两表解决方案的数据库,当它最初被采用时,这是一个很好的解决方案(为什么不必重复所有关于地址和联系的逻辑?),但是今天看起来很笨拙(因为“公司”表包含的字段仅对X和Y分别有意义)。

Probably the easiest to deal with in my case, if we migrated, would be the four-table solution: keep contacts for X-type companies totally separate from contacts for Y-type companies. 对于我来说,如果迁移,最容易处理的是四表解决方案:将X型公司的联系人与Y型公司的联系人完全分开。 If you start with your current approach then the five-table solution would be the obvious generalization if you face similar growing pains in your application. 如果您从当前的方法开始,那么如果您在应用程序中遇到类似的麻烦,那么五表解决方案将是显而易见的概括。

As for tracking phone numbers, you have some limited options: 至于跟踪电话号码,您有一些有限的选择:

  1. Store a bunch of columns in the Contacts table, one for each separate phone number. 在联系人表中存储一堆列,每个单独的电话号码一个。 This gets ugly real fast but it's the quick-and-easy way to do it. 这很快变得很丑陋,但这是快速简便的方法。 This is called "denormalized" data. 这称为“非规格化”数据。
  2. Store JSON in a text field in the Contacts list. 将JSON存储在“联系人”列表中的文本字段中。 Phone numbers are unlikely to be searched over much; 电话号码不太可能被搜索太多; it's just not very common to say "I have this number, who does it belong to?", so you can easily denormalize. 说“我有这个数字,它属于谁?”并不是很常见,因此您可以轻松地将其归一化。 This also lets you do things like {"mon thru thurs": 12025551234, "fri, sat": 12025554321} , storing simple custom annotations for the numbers. 这也使您可以执行{"mon thru thurs": 12025551234, "fri, sat": 12025554321} ,为数字存储简单的自定义注释。
  3. Create a phone table, like you've done now. 像现在一样创建电话表。 This is the most general way to do this, and if you need those sorts of annotations you can add another text field to that table. 这是执行此操作的最通用方法,如果您需要这些类型的注释,则可以在该表中添加另一个文本字段。

If you mix option 3 here with option 3 above (four tables plus an explicit phone table) then you'll probably want to have separate phone tables as well as separate contact tables; 如果将此处的选项3与上面的选项3(四个表加一个显式电话表)混合使用,那么您可能希望拥有单独的电话表和单独的联系表; Px and Py each with a foreign key to Cx and Cy. Px和Py分别具有指向Cx和Cy的外键。

To me Company and Supplier models could be the same. 对我而言, CompanySupplier模型可以相同。 Since most suppliers are companies right? 既然大多数供应商都是对的公司? If they are basically the same than merge Company and Supplier models like this: 如果它们与合并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)

This is Chris Drosts '2 table' solution. 这是Chris Drosts的“两张桌子”解决方案。 If you need supplier specific fields than add a Supplier model and link it to Company with a OneToOne: 如果您需要供应商特定的字段,而不是添加供应商模型并通过OneToOne将其链接到Company:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM