Python Django按子类名称筛选基类

Python Django按子类名称筛选基类,python,django,django-models,Python,Django,Django Models,我在Django中有以下模型继承结构: class Parent(models.Model): # stuff class A(Parent): # stuff class B(Parent): # stuff class C(Parent): # stuff and the list goes on. 我正在使用django模型utils的InheritanceManager来过滤以下对象: Parent.objects.filter(foo=bar)

我在Django中有以下模型继承结构:

class Parent(models.Model):
    # stuff

class A(Parent):
    # stuff

class B(Parent):
    # stuff

class C(Parent):
    # stuff

and the list goes on.
我正在使用django模型utils的InheritanceManager来过滤以下对象:

Parent.objects.filter(foo=bar).select_subclasses()
当我想过滤所有的子类时,这很有效。我想做的是过滤A和B对象,而不是C对象。我想用一个查询来实现这一点,比如

Parent.objects.filter(foo=bar, __class__.__name__=A, __class__.__name__=B).select_subclasses()

是否可以执行这样的筛选操作?如果可能,如何执行?

通常不认为最好设置可继承,因为这样每个SQL查询都必须执行联接。这会使您的性能大大降低。要提高性能,您可以使用
abstract
Meta-value:

class Parent(models.Model):
    # stuff
    class Meta:
        abstract = True
这样,每个表都是独立的,因此性能会更快

如果这不适用于您,我认为不可能在单个查询中执行类似的操作,因为表/模型中的字段不包含它们所在的表中的任何信息。在这种情况下,您很可能必须以某种方式对继承管理器进行子类化,但是我不确定该怎么做。如果是这样,那么使用内容类型可能会有所帮助

如果这是太多的工作,那么你总是可以做一个简单的黑客(更多的猴子补丁…)。我知道它不漂亮,但它会起作用:

class Parent(models.Model):
    # stuff
    table = models.CharField(max_length=8, default='parent')

class A(Parent):
    # stuff
    table = models.CharField(max_length=8, default='a')

class B(Parent):
    # stuff
    table = models.CharField(max_length=8, default='b')


# and then something like
# please note that I've never used django-model-utils
# so don't know the correct syntax
Parent.objects.filter(foo=bar, table__in=['parent', 'a']).select_subclasses()

另一个对我有用的黑客解决方案,没有向数据库添加更多信息:

letters = Parent.objects.filter(foo=bar)
for letter in letters:
    if type(letter) == C:
        letters.exclude(id=c.id)
或者,如果向模型中添加信息而不添加字段:

class Parent(models.Model):
    # stuff

class A(Parent):
    code = 'A'
    # stuff

class B(Parent):
    code = 'B'
    # stuff

class C(Parent):
    code = 'C'
    # stuff
然后

letters = Parent.objects.filter(foo=bar)
for letter in letters:
    if letter.child().code == 'C':
        letters.exclude(id=c.id)

就我的目的而言,这是可行的,尽管它仍然是一个黑客…

在一个查询中当然可以做到这一点

这一切都来自Django构建字段的方式,以引用父模型和子模型之间的关系。每个子项都有某种类型的
父项ref
,它有一个
相关的\u名称
。您可以查询这些

您可能会发现启动
/manage.py shell
,导入父模型类,然后执行无意义查询是最简单的:

Parent.objects.filter(foo='bar')
这将向您显示可用于查询的字段:然后您可以确定如何构建查询:

Parent.objects.filter(is_active=True).filter(
    models.Q(a__isnull=False) |
    models.Q(b__isnull=False)
).select_subclasses()
这将执行一个查询,该查询将获取a的所有对象,B的所有对象,这些对象的
处于活动状态
设置为
True
,并向下转换它们

值得指出的是,
.select\u subclass()
无法检测将包含哪些模型,因此它将加入所有子类

然而。。。您可以将值传递给
select_子类
,这样它只会连接(和向下转换)到这些子类:

Parent.objects.filter(is_active=True).filter(
    models.Q(a__isnull=False) |
    models.Q(b__isnull=False)
).select_subclasses('a', 'b')

现在,我们不再加入表“c”到“z”

为什么不直接执行
A.objects.filter(foo=bar)
etc?我想用一个查询过滤所有对象,而不是多个查询OK谢谢。我没有使用抽象基类,因为我希望能够使用单个查询过滤基类对象,而不是对每个子类使用单独的查询。我只是想在一些地方过滤基类的子集,在另一个地方过滤另一个子集。如果我找到了一个满意的解决方案,我会在这里发布。抽象继承和多表继承有着明显不同的属性。正如OP所建议的,当您希望能够执行单个查询以获取一系列不同类型时,使用MTI是合适的。当然,加入表可能会受到惩罚,但数据库在处理这方面非常出色(而且它总是能够击败单独的查询)。哇,我问这个问题已经有一段时间了:)您的回答直接解决了问题中提到的问题,谢谢。