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

时间:2021-12-09 11:32:03

I have this use case scenario: there are places which are either playgrounds, restaurants, theatres, pubs. the same place can have playgrounds, restaurants, theatres etc. there are couple of ways of implementing it:

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

  1. use foreign keys

    使用外键

    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. multitable inheritance

    多重继承

    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. use abstract class

    使用抽象类

    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. use proxy models

    使用代理模型

    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
    

What are the pros and cons of using each approach?

使用每种方法有哪些优缺点?

4 个解决方案

#1


15  

The first one is essentially model inheritance, because that's what Django's implementation of MTI uses (except it's a OneToOneField instead of a ForeignKey, but that's merely a ForeignKey that's unique).

第一个基本上是模型继承,因为这是Django对MTI的实现所使用的(除了它是OneToOneField而不是ForeignKey,但这只是一个独特的ForeignKey)。

Anytime you have an is-a relationship (i.e., a Restaurant is a Place), you're dealing with inheritance, so using one of Django's model inheritance methodologies is the way to go. Each, however, has its pros and cons:

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

Abstract Models

抽象模型

Abstract models are useful when you just want to off-load repetitive fields and/or methods. They're best used as mixins, more than true "parents". For example, all of these models will have an address, so creating an abstract Address model and having each inherit from that might be a useful thing. But, a Restaurant is not an Address, per se, so this is not a true parent-child relationship.

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

MTI (Multiple Table Inheritance)

MTI(多表继承)

This is the one that's akin to your first choice above. This is most useful when you need to interact with both the parent and child classes and the children have unique fields of their own (fields, not methods). So a Restaurant might have a cuisine field, but a Place wouldn't need that. However, they both have an address, so Restaurant inherits and builds off of Place.

这是与您上面的第一选择相似的那个。当您需要与父类和子类进行交互并且子项具有自己的唯一字段(字段,而不是方法)时,这非常有用。所以餐厅可能有一个美食场,但一个地方不需要那个。但是,他们都有一个地址,所以餐厅继承并建立了地方。

Proxy Models

代理模型

Proxy models are like aliases. They cannot have their own fields, they only get the fields of the parent. However, they can have their own methods, so these are useful when you need to differentiate kinds of the same thing. For example, I might create proxy models like StaffUser and NormalUser from User. There's still only one user table, but I can now add unique methods to each, create two different admin views, etc.

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

For your scenario, proxy models don't make much sense. The children are inherently more complicated than the parent and it wouldn't make sense to store all the fields like cuisine for Restaurant on Place.

对于您的方案,代理模型没有多大意义。这些孩子本质上比父母更复杂,所以将所有的田地都放在餐厅就餐上就没有意义了。

You could use an abstract Place model, but then you lose the ability to actually work Place on its own. When you want a foreign key to a generalized "place", you'll have to use generic foreign keys, instead, to be able to choose from among the different place types, and that adds a lot of overhead, if it's not necessary.

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

Your best bet is using normal inheritance: MTI. You can then create a foreign key to Place and add anything that is a child of Place.

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

#2


1  

It depends entirely on what sort of behaviour you need.

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

Do you need to perform the same kinds of operations on places and restaurants or playgrounds? Will you be checking if your services (restaurants etc) are in the same place? Is it meaningful to treat two places with the same address as being different, and their associated services as different?

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

Without knowing the answers to these sorts of questions, it is impossible to say which is the most appropriate technique, as they are very different techniques, and not in general substitutes for each other.

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

The use of inheritance should not be dictated by an pre-conceived notion about taxonomy, because it is not there to model taxonomy: it is there to provide function polymorphism (data member inheritance is there primarily to facilitate that).

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

#3


0  

I'd vote for an abstract class if the domain dictates that a place cannot exist if it is not at least one of the others.

如果域名规定如果一个地方不是至少其中一个地方就不存在,我会投票给一个抽象类。

But if a place doesn't need to have anything on it you'd need multiple inheritance to accomodate the placemarkers (vacant lots)?

但如果一个地方不需要任何东西,你需要多重继承来容纳地方标记(空地)?

I imagine the pro's and con's revolve around your fondness of spurious database tables. How does the ORM implement these solutions? Personally i'm not fond of having lots of single field tables but ymmv.

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

#4


0  

I'd vote for the first one, because it's the most explicit. And I don't see any advatages of other methods.

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

#1


15  

The first one is essentially model inheritance, because that's what Django's implementation of MTI uses (except it's a OneToOneField instead of a ForeignKey, but that's merely a ForeignKey that's unique).

第一个基本上是模型继承,因为这是Django对MTI的实现所使用的(除了它是OneToOneField而不是ForeignKey,但这只是一个独特的ForeignKey)。

Anytime you have an is-a relationship (i.e., a Restaurant is a Place), you're dealing with inheritance, so using one of Django's model inheritance methodologies is the way to go. Each, however, has its pros and cons:

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

Abstract Models

抽象模型

Abstract models are useful when you just want to off-load repetitive fields and/or methods. They're best used as mixins, more than true "parents". For example, all of these models will have an address, so creating an abstract Address model and having each inherit from that might be a useful thing. But, a Restaurant is not an Address, per se, so this is not a true parent-child relationship.

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

MTI (Multiple Table Inheritance)

MTI(多表继承)

This is the one that's akin to your first choice above. This is most useful when you need to interact with both the parent and child classes and the children have unique fields of their own (fields, not methods). So a Restaurant might have a cuisine field, but a Place wouldn't need that. However, they both have an address, so Restaurant inherits and builds off of Place.

这是与您上面的第一选择相似的那个。当您需要与父类和子类进行交互并且子项具有自己的唯一字段(字段,而不是方法)时,这非常有用。所以餐厅可能有一个美食场,但一个地方不需要那个。但是,他们都有一个地址,所以餐厅继承并建立了地方。

Proxy Models

代理模型

Proxy models are like aliases. They cannot have their own fields, they only get the fields of the parent. However, they can have their own methods, so these are useful when you need to differentiate kinds of the same thing. For example, I might create proxy models like StaffUser and NormalUser from User. There's still only one user table, but I can now add unique methods to each, create two different admin views, etc.

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

For your scenario, proxy models don't make much sense. The children are inherently more complicated than the parent and it wouldn't make sense to store all the fields like cuisine for Restaurant on Place.

对于您的方案,代理模型没有多大意义。这些孩子本质上比父母更复杂,所以将所有的田地都放在餐厅就餐上就没有意义了。

You could use an abstract Place model, but then you lose the ability to actually work Place on its own. When you want a foreign key to a generalized "place", you'll have to use generic foreign keys, instead, to be able to choose from among the different place types, and that adds a lot of overhead, if it's not necessary.

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

Your best bet is using normal inheritance: MTI. You can then create a foreign key to Place and add anything that is a child of Place.

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

#2


1  

It depends entirely on what sort of behaviour you need.

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

Do you need to perform the same kinds of operations on places and restaurants or playgrounds? Will you be checking if your services (restaurants etc) are in the same place? Is it meaningful to treat two places with the same address as being different, and their associated services as different?

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

Without knowing the answers to these sorts of questions, it is impossible to say which is the most appropriate technique, as they are very different techniques, and not in general substitutes for each other.

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

The use of inheritance should not be dictated by an pre-conceived notion about taxonomy, because it is not there to model taxonomy: it is there to provide function polymorphism (data member inheritance is there primarily to facilitate that).

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

#3


0  

I'd vote for an abstract class if the domain dictates that a place cannot exist if it is not at least one of the others.

如果域名规定如果一个地方不是至少其中一个地方就不存在,我会投票给一个抽象类。

But if a place doesn't need to have anything on it you'd need multiple inheritance to accomodate the placemarkers (vacant lots)?

但如果一个地方不需要任何东西,你需要多重继承来容纳地方标记(空地)?

I imagine the pro's and con's revolve around your fondness of spurious database tables. How does the ORM implement these solutions? Personally i'm not fond of having lots of single field tables but ymmv.

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

#4


0  

I'd vote for the first one, because it's the most explicit. And I don't see any advatages of other methods.

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