使用数组中的值过滤Django数据库字段

43 投票
3 回答
58507 浏览
提问于 2025-04-17 10:44

我有一个Django模型,其中有一个字段用来表示用户的全名。我的客户希望我设置一个过滤器,可以根据一个字符串数组来搜索用户,这个数组中的所有字符串都必须不区分大小写地包含在全名中。

举个例子:

如果一个用户的 full_name = "Keith, Thomson S."

而我有一个列表 ['keith','s','thomson']

我想执行一个过滤操作,效果相当于:

Profile.objects.filter(full_name__icontains='keith',full_name__icontains='s',full_name__icontains='thomson')

问题是,这个列表的大小是动态的——所以我不知道该怎么做。

有没有人有什么想法?

3 个回答

2

大概是这样的:


array = ['keith', 's', 'thomson']
regex = '^.*(%s).*$' % '|'.join(array)
Profile.objects.filter(full_name__iregex=regex)

编辑:这个说法不对,提问者想要的是包含所有字符串的名字。

13

使用 operator 函数中的 and_or_ 来组合 Q() 条件,可以让代码更简洁。

from operator import and_, or_
li = ['keith', 's', 'thompson']

匹配所有字符串的项目(使用 and_

Profile.objects.filter(reduce(and_, [Q(full_name__icontains=q) for q in li]))

匹配任意字符串的项目(使用 or_

Profile.objects.filter(reduce(or_, [Q(full_name__icontains=q) for q in li]))

Q() 函数实现了 __or__()__and__(),可以把两个 Q() 对象连接在一起,因此可以用相应的 operator 函数来调用它们。

74

可以连续调用 filter,像这样:

queryset = Profile.objects.all()
strings = ['keith', 's', 'thompson']
for string in strings:
    queryset = queryset.filter(full_name__icontains=string)

或者,你可以把一堆 Q 对象用 & 连接起来:

condition = Q(full_name__icontains=s[0])
for string in strings[1:]:
    condition &= Q(full_name__icontains=string)
queryset = Profile.objects.filter(condition) 

还有一种更复杂的写法,可以避免显式的循环:

import operator
# ...
condition = reduce(operator.and_, [Q(full_name__icontains=s) for s in strings])
queryset = Profile.objects.filter(condition)

撰写回答