假设我有一个抽象基类,看起来像这样:
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()
型
它当然会返回一个错误,因为抽象类不是一个实际的数据库对象,因此不能被查询。我读到的所有东西都说我需要做两个查询,一个在Planets上,一个在Stars上,然后合并它们。这看起来非常低效。这是唯一的方法吗?
7条答案
按热度按时间ny6fqffe1#
从根本上说,这是对象和关系数据库之间不匹配的一部分。ORM在抽象出差异方面做得很好,但有时你还是会遇到它们。
基本上,您必须在抽象继承和多表继承之间做出选择,在抽象继承的情况下,两个类之间没有数据库关系,而多表继承则以每个查询的效率为代价(额外的数据库连接)来保持数据库关系。
8qgya5xd2#
你不能查询抽象基类。对于多表继承,你可以使用django-model-utils和它的
InheritanceManager
,它用select_subclasses()
方法扩展了标准的QuerySet
,它做了你需要的正确的事情:它左连接所有继承的表,并为每行返回适当的类型示例。p5cysglq3#
这是模型中 * 多态性 * 的一个例子(多态性-一个的多种形式)。
选项1 -如果您只能在一个地方处理此问题:
为了在一两个地方使用一点if-else代码,只需手动处理它-它可能会在开发/维护方面更快,更清晰(即,除非这些查询严重影响您的数据库,否则可能值得这样做-这是您的判断,取决于情况)。
选项2 -如果你经常这样做,或者真的要求查询语法优雅:
幸运的是,django中有一个处理多态性的库,django-polymorphic-这些文档会告诉你如何精确地做到这一点。这可能是你所描述的直接查询的“正确答案”,特别是如果你想在很多地方做模型继承。
选项3 -如果您想要中途之家:
这种方法有上述两种方法的缺点,但我过去已经成功地使用它来自动将多个查询集的所有数据压缩到一起,同时保持了一个查询集对象包含两种类型模型的优点。
查看django-querysetsequence,它管理多个查询集的合并。
它没有
django-polymorphic
那么好的支持和稳定,但仍然值得一提。xbp102n04#
如果你需要在基类上查询,不要使用抽象基类,而要使用具体基类。
uoifb46i5#
在这种情况下,我认为没有其他办法。
为了优化,您可以避免从抽象
StellarObject
继承,并将其用作通过FK连接到Star
和Planet
对象的单独表。这样,它们都将具有ie.
star.stellar_info.description
。另一种方法是添加额外的模型来处理信息,并在many2many关系中使用StellarObject作为
through
。l7mqbcuq6#
如果你希望根据对象的子类将不同的子类行为绑定到对象上,我会考虑放弃抽象继承模式或具体的基础模式。
当你通过父类进行查询时--听起来你想这样做-- Django将结果对象视为父类的对象,因此访问子类级方法需要将对象重新转换到它们的“正确”子类中,这样它们就可以看到这些方法.
如果上面描述的子类行为不是问题,您可以考虑附加到抽象基类的自定义管理器,通过原始SQL将模型缝合在一起。
如果您主要对将一组离散的相同数据字段分配给一组对象感兴趣,我会将沿着一个外键,就像bx 2建议的那样。
qv7cva1a7#
效率太低了。这是唯一的办法吗?
据我所知,这是Django的ORM的唯一方法。目前实现的抽象类是一种方便的机制,可以将类的公共属性抽象为超类。ORM没有提供类似的查询抽象。
你最好使用另一种机制来实现数据库中的层次结构。一种方法是使用单个表并使用类型“标记”行。或者你可以实现另一个拥有属性的模型的通用外键(后者甚至对我来说听起来都不正确)。