如果有一个子类实例,我如何查询模型?

时间:2022-04-28 08:33:14

I have these two simple models, A and B:

我有两个简单的模型,A和B:

from django.db import models

class A(models.Model):
  name = models.CharField(max_length=10)

class B(A):
  age = models.IntegerField()

Now, how can I query for all instances of A which do not have an instance of B?

现在,我如何查询一个没有B实例的所有实例?

The only way I found requires an explicitly unique field on each subclass, which is NOT NULL, so that I can do A.objects.filter(b__this_is_a_b=None), for example, to get instances that are not also B instances. I'm looking for a way to do this without adding an explicit silly flag like that.

我发现的惟一方法是在每个子类上显式地设置唯一的字段,这不是NULL,这样我就可以做A.objects.filter(b__this_is_a_b=None),例如,获取不属于B实例的实例。我在寻找一种方法来做到这一点,而不需要添加一个明显的愚蠢的标志。

I also don't want to query for all of the objects and then filter them in Python. I want to get the DB to do it for me, which is basically something like SELECT * FROM A WHERE A.id in (SELECT id from B)

我也不想查询所有的对象,然后用Python来过滤它们。我想让DB为我做,这基本上是像SELECT * FROM A。id(从B中选择id)

3 个解决方案

#1


2  

Since some version of django or python this works as well:

因为django或python的某些版本同样适用:

A.Objects.all().filter(b__isnull=True)

because if a is an A object a.b gives the subclass B of a when it exists

因为a是a物体。b在存在的时候给出a的子类b。

I Know this is an old question, but my answer might help new searchers on this subject.

我知道这是一个老问题,但我的回答可能会帮助新的搜索者在这个问题上。

see also:

参见:

multi table inheritance

多表继承

And one of my own questions about this: downcasting a super class to a sub class

我自己的一个问题是:将一个超类降级为一个子类。

#2


1  

I'm not sure it's possible to do this purely in the DB with Django's ORM, in a single query. Here's the best I've been able to do:

我不确定是否可以在一个查询中使用Django的ORM来实现这一点。这是我能做的最好的事情:

A.objects.exclude(id__in=[r[0] for r in B.objects.values_list("a_ptr_id")])

This is 2 DB queries, and works best with a simplistic inheritance graph - each subclass of A would require a new database query.

这是两个DB查询,最好使用一个简单的继承图——每个子类都需要一个新的数据库查询。


Okay, it took a lot of trial and error, but I have a solution. It's ugly as all hell, and the SQL is probably worse than just going with two queries, but you can do something like so:

这需要很多的尝试和错误,但我有一个解决方案。它很丑,而且SQL可能比两个查询更糟糕,但是你可以这样做:

A.objects.exclude(b__age__isnull=True).exclude(b__age_isnull=False)

There's no way to get Django to do the join without referencing a field on b. But with these successive .exclude()s, you make any A with a B subclass match one or the other of the excludes. All you're left with are A's without a B subclass.

如果没有引用b中的字段,就没有办法让Django执行join操作,但是使用这些连续的.exclude()s,您可以使任何a与b子类匹配一个或另一个不包含。只剩下A没有B子类。

Anyway, this is an interesting use case, you should bring it up on django-dev...

不管怎样,这是一个有趣的用例,你应该把它提上django-dev…

#3


0  

I don't work with django, but it looks like you want the isinstance(obj, type) built-in python method.

我不使用django,但是看起来您想要的是isinstance(obj, type)内置的python方法。

Edit:
Would A.objects.exclude(id__exact=B__id) work?

编辑:A.objects.exclude(id__exact = B__id)工作?

#1


2  

Since some version of django or python this works as well:

因为django或python的某些版本同样适用:

A.Objects.all().filter(b__isnull=True)

because if a is an A object a.b gives the subclass B of a when it exists

因为a是a物体。b在存在的时候给出a的子类b。

I Know this is an old question, but my answer might help new searchers on this subject.

我知道这是一个老问题,但我的回答可能会帮助新的搜索者在这个问题上。

see also:

参见:

multi table inheritance

多表继承

And one of my own questions about this: downcasting a super class to a sub class

我自己的一个问题是:将一个超类降级为一个子类。

#2


1  

I'm not sure it's possible to do this purely in the DB with Django's ORM, in a single query. Here's the best I've been able to do:

我不确定是否可以在一个查询中使用Django的ORM来实现这一点。这是我能做的最好的事情:

A.objects.exclude(id__in=[r[0] for r in B.objects.values_list("a_ptr_id")])

This is 2 DB queries, and works best with a simplistic inheritance graph - each subclass of A would require a new database query.

这是两个DB查询,最好使用一个简单的继承图——每个子类都需要一个新的数据库查询。


Okay, it took a lot of trial and error, but I have a solution. It's ugly as all hell, and the SQL is probably worse than just going with two queries, but you can do something like so:

这需要很多的尝试和错误,但我有一个解决方案。它很丑,而且SQL可能比两个查询更糟糕,但是你可以这样做:

A.objects.exclude(b__age__isnull=True).exclude(b__age_isnull=False)

There's no way to get Django to do the join without referencing a field on b. But with these successive .exclude()s, you make any A with a B subclass match one or the other of the excludes. All you're left with are A's without a B subclass.

如果没有引用b中的字段,就没有办法让Django执行join操作,但是使用这些连续的.exclude()s,您可以使任何a与b子类匹配一个或另一个不包含。只剩下A没有B子类。

Anyway, this is an interesting use case, you should bring it up on django-dev...

不管怎样,这是一个有趣的用例,你应该把它提上django-dev…

#3


0  

I don't work with django, but it looks like you want the isinstance(obj, type) built-in python method.

我不使用django,但是看起来您想要的是isinstance(obj, type)内置的python方法。

Edit:
Would A.objects.exclude(id__exact=B__id) work?

编辑:A.objects.exclude(id__exact = B__id)工作?