Django管理员用^和=运算符搜索多词短语

时间:2017-09-28 04:06:07

标签: python django

假设模型管理员具有:

search_fields = ("^name", "=kind")

如果name"Leonardo Da Vinci",则可以使用查询LeonLeonardo找到它,但不能找到Leonardo DaLeonardo Da Vinci。如果是kind,例如"polymath genius",无法在任何查询中找到此类值。理想情况下,人们可以发布"multiple words" "Leonardo Da"并获得此记录;但鉴于Django如何分割查询,它并没有做到人们所期望的。

9年前this ticket显然提出了这个问题并解决了。然后Django被重写了,显然这已经被丢弃了。

有没有人知道这是否可行?我可能以为我需要覆盖ModelAdmin.get_search_results ......还有什么更优雅的吗?

1 个答案:

答案 0 :(得分:0)

这是我能想到的最好的。我真的不喜欢它,因为如果Django更新它看起来可能会失败。它有很多复制意大利面,基本上只是换一行(for bit in search_term.split():

from django.utils.text import smart_split, unescape_string_literal
from django.db import models
from functools import reduce
import operator
from django.contrib.admin.utils import lookup_needs_distinct

class QuotedSearchModelAdmin(admin.ModelAdmin):
    def get_search_results(self, request, queryset, search_term):
        """
        Returns a tuple containing a queryset to implement the search,
        and a boolean indicating if the results may contain duplicates.
        """
        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        # Group using quotes
        def unescape_string_literal_if_possible(bit):
            try:
                return unescape_string_literal(bit)
            except ValueError:
                return bit

        use_distinct = False
        search_fields = self.get_search_fields(request)
        if search_fields and search_term:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in search_fields]
            search_term_list = [unescape_string_literal_if_possible(bit)
                                for bit in smart_split(search_term)]
            for bit in search_term_list:
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break

        return queryset, use_distinct