【问题标题】:How to override Django get_search_results method in ModelAdmin, while keeping filters working as expected?如何在 ModelAdmin 中覆盖 Django get_search_results 方法,同时保持过滤器按预期工作?
【发布时间】:2020-10-28 11:14:10
【问题描述】:

我有一个模型管理员,我以这种方式覆盖 get_search_result

def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super(OccupancyAdmin, self).get_search_results(
            request, queryset, search_term
        )
        search_words = search_term.split(",")
        if search_words:
            q_objects = [
                Q(**{field + "__icontains": word})
                for field in self.search_fields
                for word in search_words
            ]
            queryset |= self.model.objects.filter(reduce(or_, q_objects))
        return queryset, use_distinct

建议来自这里:Is there a way to search for multiple terms in admin search? django

我面临的问题如下:来自rangefilterDateTimeRangeFilter 和我的自定义SimpleListFilter 都不再按预期工作了。过滤器似乎被禁用了。

我查看了正在执行的 SQL 查询,它们看起来还不错。

我很确定我以某种方式弄乱了查询集,但不知道如何调试。

【问题讨论】:

    标签: python django django-admin django-filter


    【解决方案1】:

    对我有用的是在 super() 之前声明一个原始查询集,最后拦截两个查询集:

    def get_search_results(self, request, queryset, search_term):
        orig_queryset = queryset
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
        search_words = search_term.split(",")
        if search_words:
            q_objects = [
                Q(**{field + "__icontains": word})
                for field in self.search_fields
                for word in search_words
            ]
            queryset |= self.model.objects.filter(reduce(or_, q_objects))
    
        queryset = queryset & orig_queryset
    
        return queryset, use_distinct
    

    否则,使用@simon-spa 的答案,通过修改后的get_search_results() 执行的任何修改都将被忽略(但过滤器确实可以工作)。

    【讨论】:

      【解决方案2】:

      Django 首先应用过滤器,然后将结果查询集传递给搜索方法。在您的代码中,您通过 self.model.objects.filter() 向查询集添加了其他对象,这基本上使过滤器无用。

      如果您仅将过滤器应用于当前查询集,则它可以工作:

      def get_search_results(self, request, queryset, search_term):
          queryset, use_distinct = super().get_search_results(request, queryset, search_term)
          search_words = search_term.split(",")
          if search_words:
              q_objects = [
                  Q(**{field + "__icontains": word})
                  for field in self.search_fields
                  for word in search_words
              ]
              queryset = queryset.filter(reduce(or_, q_objects))
          return queryset, use_distinct
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-01
        • 2013-09-21
        • 1970-01-01
        相关资源
        最近更新 更多