在Django中搜索多个模型中的字段

时间:2015-06-23 14:05:07

标签: python django django-models django-rest-framework

假设,

名为Education的模型包含字段degreefield,其他模型Resume包含字段skillrole。< / p>

第三个模型是Candidates,并且与上述模型具有外键关系。

我希望用户按skillroledegreefield搜索候选人。

例如:如果传递了像{'java','developer','MS','IT'}这样的查询字符串,Django应该显示匹配查询字符串中任何一个值的所有候选字符。

3 个答案:

答案 0 :(得分:0)

我认为在django中有一种自动方式可以做到这一点。但是你总是可以使用Q一起进行OR多次搜索.Q的基本用法如下:

from django.db.models import Q
Education.objects.filter(
    Q(degree__icontains=query) | Q(field__icontains=query)

要使用多个查询,您可以使用for语句轻松地将这些语句组合在一起(假设查询是一个列表或一组查询字符串):

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)

答案 1 :(得分:0)

如果您使用Django Rest Framework(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请求如下:

http://www.example.com/rest/SampleSet/?multi_field_srch=foo,de,fa,fa

将返回所有 SampleSetfoo {{1}的所有de至少在其中一个字段fafield_foobar中。

如果您将参数baz指定为token_reducer,则该查询将返回任何 operator.or_的所有SampleSet,{至少有一个字段foodefa中的{1}}, field_foo

最后,barbaz是一种插入通配符(子字符串匹配)或其他前缀或后缀的方法。

答案 2 :(得分:0)

我正在使用Django Rest Multiple Models在Django Rest Framework中搜索多个模型。请务必仔细阅读文档,尤其是section on using viewsets,它解释了如何设置端点。它看起来真的很好构建并记录在案,并且可以支持我期望的所有内容,例如限制和过滤器。