哪个更好:外键或模型继承?

时间:2012-01-20 04:31:21

标签: django django-models

我有这个用例场景: 有些地方是游乐场,餐馆,剧院,酒吧。 相同的place可以有游乐场,餐馆,剧院等。 有几种方法可以实现它:

  1. 使用外键

    class Place(models.Model):
        name = models.CharField(max_length=50)
    
    class PlayGrounds(models.Model)
        field1 = models.CharField(max_length=50)
        place = models.ForeignKey(Place)
    
  2. 多元继承

    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)
    
    class Restaurant(Place):
        serves_hot_dogs = models.BooleanField()
        serves_pizza = models.BooleanField()
    
  3. 使用抽象类

    class Place(models.Model):
        name = models.CharField(max_length=50)
    
    class PlayGrounds(Place)
        field1 = models.CharField(max_length=50)
        place = models.ForeignKey(Place)
        class Meta:
            abstract = True
    
  4. 使用代理模型

    class Place(models.Model):
        name = models.CharField(max_length=50)
    
    class PlayGrounds(Place)
        field1 = models.CharField(max_length=50)
        place = models.ForeignKey(Place)
        class Meta:
            proxy = True
    
  5. 使用每种方法有哪些优缺点?

4 个答案:

答案 0 :(得分:15)

第一个 本质上是模型继承,因为这是Django对MTI的实现所使用的(除了OneToOneField而不是ForeignKey,但这只是{{} 1}}这是唯一的。)

只要你有一个 is-a 关系(即,一个餐馆就是一个地方),你就是在处理继承,所以使用Django的模型继承方法之一就是要走的路。然而,每个都有其优点和缺点:

抽象模型

当您只想卸载重复的字段和/或方法时,抽象模型很有用。他们最好用作mixins,而不仅仅是真正的“父母”。例如,所有这些模型都有一个地址,因此创建一个抽象的ForeignKey模型并从中继承每个模型可能是一个有用的东西。但是,Address本身不是Restaurant,所以这不是真正的亲子关系。

MTI(多表继承)

这是与您上面的第一个选择类似的选项。当您需要与父类和子类进行交互并且子项具有自己的唯一字段(字段,而不是方法)时,这非常有用。因此,Address可能包含Restaurant字段,但cuisine不需要该字段。但是,它们都有一个地址,因此Place继承并构建Restaurant

代理模型

代理模型就像别名。他们不能拥有自己的领域,只能获得父级的领域。但是,它们可以有自己的方法,因此当您需要区分相同的东西时,这些方法很有用。例如,我可以从Place创建代理模型,如StaffUserNormalUser。仍然只有一个用户表,但我现在可以为每个用户表添加独特的方法,创建两个不同的管理员视图等。

对于您的方案,代理模型没有多大意义。这些孩子本质上比父母更复杂,将User的{​​{1}}等所有字段存储在cuisine上是没有意义的。

可以使用抽象的Restaurant模型,但是你失去了自己实际工作Place的能力。当你想要一个外键到一个通用的“地方”时,你将不得不使用通用的外键,而是能够从不同的地方类型中进行选择,如果没有必要,会增加很多开销。

你最好的选择是使用正常继承:MTI。然后,您可以为Place创建一个外键,并添加Place的子项。

答案 1 :(得分:1)

这完全取决于您需要什么样的行为。

您是否需要在地方,餐馆或游乐场进行相同的操作? 您是否会检查您的服务(餐馆等)是否在同一个地方?将具有相同地址的两个地方视为不同,并将其相关服务视为不同,这是否有意义?

如果不知道这些问题的答案,就不可能说哪种技巧最合适,因为它们是非常不同的技术,而不是一般的替代技术。

继承的使用不应该由预先设想的关于分类法的概念决定,因为不存在对分类法进行建模的原因:它提供了函数多态性(数据成员继承主要是为了促进这一点)。

答案 2 :(得分:0)

如果域名规定如果place不是至少其中一个place,那么我会投票给一个抽象类。

但如果{{1}}不需要任何东西,你需要多次继承才能容纳地方标记(空地)?

我认为专业人士和骗子围绕着你对虚假数据库表的喜爱。 ORM如何实施这些解决方案?就个人而言,我并不喜欢拥有大量的单场表,而是ymmv。

答案 3 :(得分:0)

我会投票给第一个,因为它是最明确的。我没有看到任何其他方法的优点。

相关问题