2012-01-20 62 views
11

我有一个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') 

问题是这样的名单可以动态大小 - 所以我不知道如何做到这一点。

任何人有任何想法?

回答

33

请连续调用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) 
+0

我不知道链接所有这些过滤器后,最终的sql表达式会变成什么样子。 – akonsu

+0

@akonsu我只是试了一下(好吧,类似的东西) - 它被转换为'where子句中的一系列'AND's,即'full_name LIKE%keith%AND full_name LIKE%s%AND ... ' –

+2

@isbadawi,+1 - 请注意,多个Q对象的默认运算符是AND,因此您可以在不使用reduce/operator.and_的情况下运行“* [Q1,Q2,Q3]”。 –

2

somethi ng沿着这些线:


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

编辑:这是错误的,OP想要名称,其中包含所有字符串同时。

3

使用operator功能and_or_Q()条件

匹配所有的字符串( and_

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

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

项目匹配任何字符串,该清单结合更短(or_

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

Q()函数实现__or__()__and__()连接两个Q()对象组合在一起,这样他们就可以使用相应的operator函数调用。

相关问题