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.
真的吗?如果不是,为什么这两种方法会导致不同的查询集?
关于
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
时,这将重复条目。