.filter 和 .exclude 中的多个嵌套查找之间的不同行为

问题描述 投票:0回答:1

queryset.filter
queryset.exclude
中的多个嵌套查找有什么区别?

例如汽车评级。用户可以为任何汽车创建多种类型的评级。

class Car(Model):
    ...

class Rating(Model):
    type = ForeignKey('RatingType') # names like engine, design, handling
    user = ... # user

让我们尝试获取没有用户“a”评级的汽车列表并输入“design”。

方法 1

car_ids = Car.objects.filter(
        rating__user="A",  rating__type__name="design"
    ).values_list('id',flat=True)

Car.objects.exclude(id__in=car_ids)

方法 2

Car.objects.exclude(
        rating__user="A", rating__type__name="design"
    )

方法 1 对我来说效果很好,而方法 2 看起来排除了更多的汽车。我怀疑

exclude
中的嵌套查找的行为不像 AND(对于评级),而是像 OR.

真的吗?如果不是,为什么这两种方法会导致不同的查询集?

python django django-queryset django-orm
1个回答
0
投票

关于

filter
,“multiple parameters are joined via
AND
in the underlying SQL statement
”。您的第一种方法不会产生一个而是两个 SQL 查询,大致相当于:

SELECT ... WHERE rating.user='A' AND rating.type.name='design';
SELECT ... WHERE car.id NOT IN (id1, id2, id3 ...);

这是文档的一部分,非常准确地回答了您关于

exclude
的问题: https://docs.djangoproject.com/en/stable/ref/models/querysets/#exclude

评估的 SQL 查询如下所示:

SELECT ... WHERE NOT (rating.user='A' AND rating.type.name='design')

filter
exclude
内的嵌套查找行为相似,并使用
AND
条件。在一天结束的时候,大多数时候,你的 2 种方法确实是等价的......除了
Car
表可能已经在你的方法 1 的第一个和第二个查询之间更新了。

你确定不是这样吗?可以肯定的是,尝试将方法 1 的两行包装在 transaction.atomic 块中?无论如何,您的第二种方法可能是最好的(查询越少越好)。

另外,您可能想添加一个

.distinct()
以确保获得独特的结果。实际上,当有多个
Rating
指向相同的
Car
时,这将重复条目。

如果您有任何疑问,您还可以查看已评估的查询(请参阅此处此处)。

© www.soinside.com 2019 - 2024. All rights reserved.