首页 > 解决方案 > Django通过列表中的值从数据库中查找项目?

问题描述

我有一个字符串列表:

phrases_filter = json.loads(request.GET['phrases_filter'])
['xx', 'yy']

我需要在 db 中查找所有包含xx OR的短语 yy

我试过这样:

Phrase.objects.filter(name__in phrases_filter)

但这给了我只有名字xx yy

标签: pythondjangopython-3.xdjango-queryset

解决方案


我们可以展开__contains列表,并使用或逻辑定义一组谓词:

from django.db.models import Q
from functools import reduce
from operator import or_

Phrase.objects.filter(
    reduce(or_, (Q(name__contains=e) for e in phrases_filter))
)

在给定的情况下phrases_filter,我们将生成等效于:

Phrase.objects.filter(
    Q(name__contains='xx') | Q(name__contains='yy')
)

所以reduce(..)将对对象的生成器进行操作Q(..),这里[Q(name__contains='xx'), Q(name__contains='yy')]。这些reduce(..)作品类似于函数式编程中所谓的“折叠”(这是一种变态现象的特例)。

因此,我们将or_在两者之间添加 s,从而得到Q(name__contains='xx') | Q(name__contains='yy')。这是一个基本上对过滤条件进行编码的对象:这意味着该name列应该__contains是 substring'xx'或 substring 'yy'

注意:如果您想敏感的情况下匹配大小写(因此带有XX, or Xx, or xX, or的行都是xx候选者),然后替换为.__contains__icontains

编辑:根据您的评论,如果phrases_filter为空,您希望所有行都匹配,我们可以使用以下if语句来做到这一点:

from django.db.models import Q
from functools import reduce
from operator import or_

queryset = Phrase.objects.all()
if phrases_filter:
    queryset = filter(
        reduce(or_, (Q(name__contains=e) for e in phrases_filter))
    )

因此,只有在至少phrases_filter包含一个元素的情况下,我们才会执行过滤。


推荐阅读