【问题标题】:Search fields in multiple models in Django在 Django 中的多个模型中搜索字段
【发布时间】:2015-09-09 09:13:55
【问题描述】:

假设,

名为Education 的模型包含字段degreefield,而另一个模型Resume 包含字段skillrole

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

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

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

【问题讨论】:

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


    【解决方案1】:

    如果您使用 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
    

    将返回所有SampleSet 在至少一个字段@987654334 中所有 foode fa @、barbaz

    如果您将参数token_reducer 指定为operator.or_,则该查询将返回所有具有foode任何SampleSets /em> fa 至少在 field_foobarbaz 字段之一中。

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

    【讨论】:

      【解决方案2】:

      我认为在 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)
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 2018-03-23
          • 2020-11-02
          • 1970-01-01
          • 2021-06-07
          • 1970-01-01
          • 1970-01-01
          • 2017-11-06
          • 1970-01-01
          • 2021-08-19
          相关资源
          最近更新 更多