假设,搜索字段在Django
名为Education
模型包含字段degree
和field
,和其他模型Resume
包含字段skill
和role
。
第三种模式是Candidates
并与上述机型外键关系。
我希望用户按skill
,role
,degree
或field
搜索候选人。
例如:如果传递类似{'java','developer','MS','IT'}
的查询字符串,Django应显示与查询字符串中的任何一个值匹配的所有候选字符。
假设,搜索字段在Django
名为Education
模型包含字段degree
和field
,和其他模型Resume
包含字段skill
和role
。
第三种模式是Candidates
并与上述机型外键关系。
我希望用户按skill
,role
,degree
或field
搜索候选人。
例如:如果传递类似{'java','developer','MS','IT'}
的查询字符串,Django应显示与查询字符串中的任何一个值匹配的所有候选字符。
如果你使用Django的REST框架(DRF)这样做,你将要使用django_filters为referenced by DRF。
做你在我的项目在说些什么,我创建了一个django_filters.Filter
的通用扩展:
import operator
from django.db.models import Q
import django_filters
class MultiFieldFilter(django_filters.Filter):
def __init__(self,names,*args,**kwargs):
if len(args) == 0:
kwargs['name'] = names[0]
self.token_prefix = kwargs.pop('token_prefix','')
self.token_suffix = kwargs.pop('token_suffix','')
self.token_reducer = kwargs.pop('token_reducer',operator.and_)
self.names = names
django_filters.Filter.__init__(self,*args,**kwargs)
def filter(self,qs,value):
if value not in (None,''):
tokens = value.split(',')
return qs.filter(
reduce(
self.token_reducer,
[
reduce(
operator.or_,
[Q(**{
'%s__icontains'%name:
(self.token_prefix+token+self.token_suffix)})
for name in self.names])
for token in tokens]))
return qs
这在django_filter.FilterSet
这样使用:
class SampleSetFilter(django_filters.FilterSet):
multi_field_search = MultiFieldFilter(names=["field_foo", "bar", "baz"],lookup_type='in')
class Meta:
model = SampleSet
fields = ('multi_field_srch',)
哪个实例化如:
class SampleSetViewSet(viewsets.ModelViewSet):
queryset = SampleSet.objects.all()
serializer_class = SampleSetSerializer
filter_class = SampleSetFilterSet # <- and vvvvvvvvvvvvvvvvvvvvvvvvvvvv
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend,)
最后,一个GET
请求l迈克:
http://www.example.com/rest/SampleSet/?multi_field_srch=foo,de,fa,fa
会传回的foo
,de
,和fa
所有在田里field_foo
,bar
或baz
的至少一个所有SampleSet
的。
如果指定参数token_reducer
是operator.or_
,那么查询将返回所有SampleSet
S作的foo
,de
,或fa
任何在田里field_foo
的至少一个,bar
或baz
。
最后,token_prefix
和token_suffix
是插入通配符(子字符串匹配)或其他前缀或后缀的一种方式。
我不认为有一个自动的方式在Django做到这一点。但是你可以总是或多个搜索一起使用Q. Q的基本用法如下:
from django.db.models import Q
Education.objects.filter(
Q(degree__icontains=query) | Q(field__icontains=query)
要使用的语句(假设查询是一个列表或者设置使用多个查询,你可以很容易地建立起来,这些语句的查询字符串):
q = Q()
for query in queries
q = q | Q(degree__icontains=query) | Q(field__icontains=query)
Education.objects.filter(q)
现在,您需要搜索多个模型,因此您还必须包含这些连接。这不是从你的问题十分清楚,你会如何想搜索,但我猜你想从根本上寻找候选人,所有的关键字必须被找到的项目相匹配。因此查询可以做这样的:
q = Q()
for query in queries
q = (q & (Q(education__degree__icontains=query) |
Q(education__field__icontains=query) |
Q(resume__skill__icontains=query) |
Q(resume__role__icontains=query)
Q(skill__icontains=query) |
Q(role__icontains=query) |
Q(degree__icontains=query) |
Q(field__icontains=query)))
return Candidate.objects.filter(q)