如何在Django中查询基于抽象类的对象?

Kev*_*ker 46 django abstract-class

假设我有一个如下所示的抽象基类:

class StellarObject(BaseModel):
  title = models.CharField(max_length=255)
  description = models.TextField()
  slug = models.SlugField(blank=True, null=True)

  class Meta:
    abstract = True
Run Code Online (Sandbox Code Playgroud)

现在,假设我有两个从StellarObject继承的实际数据库类

class Planet(StellarObject):
  type = models.CharField(max_length=50)
  size = models.IntegerField(max_length=10)

class Star(StellarObject):
  mass = models.IntegerField(max_length=10)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.如果我想获得行星或星星,我所做的就是:

Thing.objects.all() #or
Thing.objects.filter() #or count(), etc...
Run Code Online (Sandbox Code Playgroud)

但是如果我想获得所有StellarObjects呢?如果我做:

StellarObject.objects.all()
Run Code Online (Sandbox Code Playgroud)

它当然会返回错误,因为抽象类不是实际的数据库对象,因此无法查询.我读过的所有内容都说我需要做两个查询,一个是行星和星星,然后合并它们.这似乎非常低效.这是唯一的方法吗?

Dan*_*man 38

从根本上说,这是对象和关系数据库之间不匹配的一部分.ORM在抽象差异方面做得很好,但有时你只是反对它们.

基本上,您必须在抽象继承之间进行选择,在这种情况下,两个类之间不存在数据库关系,或多表继承,这会使数据库关系以每个查询的效率(额外的数据库连接)为代价.

  • 我最终切换到多表继承,因为它似乎是实现我所需要的例外方式.谢谢大家的回复. (2认同)

Zlo*_*erg 10

您无法查询抽象基类.对于多表继承,您可以使用django-model-utilsInheritanceManager,它QuerySet使用select_subclasses()方法扩展标准,它正确地执行您需要:它左连接所有继承的表并为每一行返回适当的类型实例.


thc*_*ark 8

这是模型中多态性的一个示例(多态性 - 一种的多种形式)。

选项 1 - 如果您只处理一个地方:

为了一两个地方的一些 if-else 代码,只需手动处理它 - 在开发/维护方面可能会更快更清晰(即可能值得,除非这些查询受到严重打击您的数据库 - 这是您的判断,取决于具体情况)。

选项 2 - 如果您经常这样做,或者确实需要查询语法的优雅:

幸运的是,有一个库可以处理django 中的多态性django-polymorphic - 这些文档将向您展示如何精确地做到这一点。正如您所描述的那样,这可能是直接查询的“正确答案”,特别是如果您想在很多地方进行模型继承。

选项 3 - 如果你想要一个中途宿舍:

这种类型具有上述两种类型的缺点,但我过去曾成功地使用它自动将多个查询集的所有压缩在一起,同时保留了一个包含两种类型模型的查询集对象的好处。

查看django-querysetsequence,它管理多个查询集的合并。

它不像 那样受支持或稳定django-polymorphic,但仍然值得一提。


Car*_*yer 5

如果需要在基类上查询,请不要使用抽象基类。请改用具体的基类。