我有一个字符串列表:
phrases_filter = json.loads(request.GET['phrases_filter'])
['xx', 'yy']
我需要在 db 中查找所有包含 xx OR yy
我试过这样的:
Phrase.objects.filter(name__in phrases_filter)
但这只给了我名称中有 xx AND yy
请您参考如下方法:
我们可以展开列表,并定义一组 __contains带或逻辑的谓词:
from django.db.models import Q
from functools import reduce
from operator import or_
Phrase.objects.filter(
<b>reduce(or_, (Q(name__contains=e) for e in phrases_filter))</b>
)
对于给定的 phrases_filter ,我们将生成等同于:
Phrase.objects.filter(
<b>Q(name__contains='xx') | Q(name__contains='yy')</b>
)
所以 reduce(..)将在 Q(..) 的生成器 上运行对象,在这里 [Q(name__contains='xx'), Q(name__contains='yy')] . reduce(..)其工作方式类似于函数式编程中所谓的“折叠”(这是变形 的特例)。
因此我们将添加 or_介于两者之间,导致 Q(name__contains='xx') | Q(name__contains='yy') .这是一个基本上对过滤条件进行编码的对象:这意味着 name列应该__contains子字符串 'xx' ,或子字符串 'yy' .
Note: in case you want to match case insensitive (so rows with
XX, orXx, orxX, orxxare all candidates), then replace__containswith__<b>i</b>contains.
编辑:根据您的评论,以防phrases_filter为空,您希望所有行都匹配,我们可以使用 if 来做到这一点声明:
from django.db.models import Q
from functools import reduce
from operator import or_
queryset = Phrase.objects<b>.all()</b>
<b>if phrases_filter:</b>
queryset = filter(
reduce(or_, (Q(name__contains=e) for e in phrases_filter))
)
所以只有以防万一phrases_filter包含 至少 个元素,我们执行过滤。
