使用数组中的值过滤Django数据库字段
我有一个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)