问题描述
如何在同一字段的 Q() 上实现 AND 查找。
class Foo(models.Model):
name = models.ManyToManyField(Type)
class Type(models.Model):
type = models.CharField()
我试过:
Foo.objects.filter(Q(name__type='any'), Q(name__type='some'))
和
Foo.objects.filter(Q(name__type='any') & Q(name__type='some'))
然而,它们都提供空的查询集。
我知道,这会起作用:
Foo.objects.filter(name__type='any').filter(name__type='some')
但是,当创建更复杂的查询时,其中Q1
、 Q2
、 Q3
是Q()
对象然后
Foo.objects.filter(Q1).filter(Q2).filter(Q3)
可以提供不同的结果
Foo.objects.filter(Q2).filter(Q3).filter(Q1)
由于应用过滤器的顺序。
更新:我意识到这个 AND 查询有效,因为 modelField 不是ManyToMany
而是CharField
:
Type.objects.filter(Q(type__icontains='some') & Q(type__icontains='thing'))
因此,仅进行 AND-Query 对多对多关系不起作用。
1楼
filter
已经是一个AND查找。
通常你会想要使用Q()
查询来组合OR查找。
我这么说是因为使用AND查找还有其他方法来组成动态查询。
预计以下查询将返回一个空的查询集:
Foo.objects.filter(Q(name__type='any') & Q(name__type='some'))
因为Type
实例被命名为“any”或“some”——它不能同时被命名,所以查询集将始终为空。
但是语法是正确的。 您可以使用它来连接多个AND查找表达式(只要它们过滤不同的字段,否则您最终可能会得到一个空的查询集)。 因为过滤器应用于数据库中的每一行。
创建复杂和动态过滤器(使用AND查找)的另一种方法是使用字典:
params = {
'first_name': 'foo',
'last_name': 'bar'
}
if condition:
params['email'] = 'foo@bar.com'
Foo.objects.filter(**params)
2楼
正如Victor Freitas已经解释过的那样,一个字段在同一个记录中不可能有两个值,但是由于你的关系是多对多的,所以可以有多个记录,因此这两个值可以存在对于同一字段,但要进行此查询,您必须使用 OR 运算符:
Foo.objects.filter(Q(name__type='any') | Q(name__type='some'))