棘手的模型继承 - Django

14 投票
4 回答
2721 浏览
提问于 2025-04-15 20:41

我觉得这个问题有点复杂,至少对我来说是这样。:)

我有四个模型,分别是歌手贝斯手忍者

歌手、贝斯手和忍者都是从人这个模型派生出来的。


问题是,每个人都可以是它的子类中的任何一个。

比如说,一个人可以既是歌手又是忍者。另一个人可以是贝斯手和忍者。还有一个人可以是这三者的结合。

我应该怎么组织我的模型呢?


非常感谢任何帮助!

4 个回答

2

我同意Alex提到的角色解决方案。你所拥有的并不是不同类型的人,而是一个人可以扮演的不同角色。

但我听到你说:“嘿,忍者可以有一个属性叫‘星星数量’,而歌手可以有一个属性叫‘最高音’。就像接口一样:忍者可以有方法throwStar()和disappear(),而歌手可以有sing()和getWasted(),贝斯手可以有goFunky()和slapPop()。”

你这里遇到的情况是,你的数据模型需要一个非常宽松的结构。宽松到实际上,你根本没有结构。如果歌手决定拿起贝斯即兴演奏,那没问题。如果他想当忍者,调用throwStar时会报错,因为他没有星星,但原则上你可以给歌手分配星星,让他也能扔星星。

你现在进入的是本体论的世界,而不是传统的结构。你有一个资源,也就是“某种东西”,这个东西可以有某种类型,拥有一些属性等等。某些属性的存在可以推断出类型,或者某种类型的存在可以推断出其他类型。用简单的django数据模型很难描述这些信息。你需要的是一个能够理解上下文并进行推理的图形存储,比如AllegroGraph,或者用rdflib实现你自己的解决方案。

3

原则上,你可以做类似下面的事情:

class Role(models.Model):       
     ......

class Ninja(Role):
     .......

class Person(models.Model):
      roles = models.ManyToManyField(Role)

但是你会遇到一个问题,Person.roles.objects.all() 只能给你角色(Role)的实例。所以你需要一个方法,把每个角色实例转换成合适的子类,比如忍者(Ninja)或海盗(Pirate)。这里有一个链接,讨论了这个问题。

http://groups.google.com/group/django-users/browse_thread/thread/f4241bc16455f92d/7268c3f7bca6b046

总之,Alex 和 Stefano 给出的答案比我更有用。

15

多重继承在数据库中不太好用(而且你的Django模型最终需要映射到数据库),而且用继承来表示“角色”通常不是个好主意(因为人的角色是会变化的)。我会把歌手、贝斯手和忍者看作“角色”,而不是作为人的子类,并通过外键来连接它们:

class Singer(models.Model):
    person = models.ForeignKey('Person')
    # ...

class Person(models.Model):
    # ...

撰写回答