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

时间:2010-09-26 13:29:36

标签: 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

现在,假设我有两个从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)

到目前为止,这么好。如果我想获得行星或星星,我所做的就是:

Thing.objects.all() #or
Thing.objects.filter() #or count(), etc...

但是如果我想获得所有StellarObjects怎么办?如果我这样做:

StellarObject.objects.all()

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

7 个答案:

答案 0 :(得分:33)

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

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

答案 1 :(得分:10)

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

答案 2 :(得分:5)

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

答案 3 :(得分:4)

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

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

为了一两个地方的一些if-else代码,只需手动处理它 - 它在开发/维护方面可能会更快更清晰(也许值得,除非这些查询正在严厉打击你的数据库 - 这是你的判断,并取决于环境)。

选项2 - 如果您执行此操作,或者在查询语法中确实要求优雅:

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

选项3 - 如果你想要一个中途的房子:

这种方法有上述两个方面的缺点,但我过去成功地使用它来自动从多个查询集中完成所有压缩,同时保持一个包含两种类型的查询集对象的好处模特。

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

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

答案 4 :(得分:1)

在这种情况下,我认为别无他法。

为了优化,您可以避免从抽象StellarObject继承并将其用作通过FK连接到StarPlanet对象的单独表。

这样他们两个都会有。 star.stellar_info.description

其他方法是添加额外的模型来处理信息,并在许多关系中使用StellarObject作为through

答案 5 :(得分:1)

如果您希望根据各自的子类将不同的子类行为绑定到对象,我会考虑放弃抽象继承模式或具体基本模式。

当您通过父类进行查询时 - 听起来您想要这样做 - Django将生成的对象视为父类的对象,因此访问子类级方法需要将对象重新转换为对象“适当的”子类即时,所以他们可以看到这些方法......在这一点上,一系列if语句悬挂在父类级方法上可以说是一种更清晰的方法。

如果上面描述的子类行为不是问题,您可以考虑附加到抽象基类的自定义管理器,通过原始SQL将模型拼接在一起。

如果您对主要为一堆对象分配一组相同的数据字段感兴趣,我会像外键一样关注,就像bx2建议的那样。

答案 6 :(得分:0)

  

这看起来非常低效。这是唯一的方法吗?

据我所知,这是Django的ORM的唯一方法。正如实现的那样,抽象类是一种方便的机制,用于将类的公共属性抽象为超类。 ORM不提供类似的查询抽象。

最好使用其他机制在数据库中实现层次结构。一种方法是使用单个表和使用类型的“标记”行。或者你可以将一个通用外键实现到另一个包含属性的模型(后者对我来说听起来不对)。