Skip to main content
 首页 » 编程设计

python之django之自定义管理搜索的最简单方法

2024年08月23日28lidabo

我正在使用 Django 1.8。 我需要的是在多个字段中执行不区分大小写的 admin-search 并允许用户使用 AND、OR 和 NOT 运算符以及一些如何使用括号或引号对单词进行分组。 搜索示例:

棉和(红色或“深蓝色”)

我已经发现了 django-advanced-filter 和 django-filter... 它们是过滤器!我还希望允许用户在搜索框中键入键。 我知道 get_search_results 允许我们覆盖搜索行为,但在我为此编写代码之前,我想问一下是否有一个包可以为我做这件事? 请注意,我觉得使用 haystack 进行自定义搜索非常复杂。

请您参考如下方法:

这answer在执行我的评论中提到的小编辑后似乎对我有用。然而,我不知道这是否是“正确”的做法。

这是适用于 django 1.8 的更新代码:

from django.contrib import admin 
from django.db import models 
from bookstore.models import Book 
from django.contrib.admin.views.main import ChangeList 
import operator 
 
class MyChangeList(ChangeList): 
    def __init__(self, *a): 
        super(MyChangeList, self).__init__(*a) 
 
    def get_queryset(self, request): 
        print dir(self) 
        # First, we collect all the declared list filters. 
        (self.filter_specs, self.has_filters, remaining_lookup_params, 
         use_distinct) = self.get_filters(request) 
 
        # Then, we let every list filter modify the queryset to its liking. 
        qs = self.root_queryset 
        for filter_spec in self.filter_specs: 
            new_qs = filter_spec.queryset(request, qs) 
            if new_qs is not None: 
                qs = new_qs 
 
        try: 
            # Finally, we apply the remaining lookup parameters from the query 
            # string (i.e. those that haven't already been processed by the 
            # filters). 
            qs = qs.filter(**remaining_lookup_params) 
        except (SuspiciousOperation, ImproperlyConfigured): 
            # Allow certain types of errors to be re-raised as-is so that the 
            # caller can treat them in a special way. 
            raise 
        except Exception, e: 
            # Every other error is caught with a naked except, because we don't 
            # have any other way of validating lookup parameters. They might be 
            # invalid if the keyword arguments are incorrect, or if the values 
            # are not in the correct type, so we might get FieldError, 
            # ValueError, ValidationError, or ?. 
            raise IncorrectLookupParameters(e) 
 
        # Use select_related() if one of the list_display options is a field 
        # with a relationship and the provided queryset doesn't already have 
        # select_related defined. 
        if not qs.query.select_related: 
            if self.list_select_related: 
                qs = qs.select_related() 
            else: 
                for field_name in self.list_display: 
                    try: 
                        field = self.lookup_opts.get_field(field_name) 
                    except Exception as ex:# models.FieldDoesNotExist: 
                        print ex 
                        pass 
                    else: 
                        if isinstance(field.rel, models.ManyToOneRel): 
                            qs = qs.select_related() 
                            break 
 
        # Set ordering. 
        ordering = self.get_ordering(request, qs) 
        qs = qs.order_by(*ordering) 
 
        # 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 
 
        if self.search_fields and self.query: 
            orm_lookups = [construct_search(str(search_field)) 
                           for search_field in self.search_fields] 
            or_queries = [] 
            for bit in self.query.split(): 
                or_queries += [models.Q(**{orm_lookup: bit}) 
                              for orm_lookup in orm_lookups] 
            if len(or_queries) > 0: 
                qs = qs.filter(reduce(operator.or_, or_queries)) 
            if not use_distinct: 
                for search_spec in orm_lookups: 
                    if admin.utils.lookup_needs_distinct(self.lookup_opts, search_spec): 
                        use_distinct = True 
                        break 
 
        if use_distinct: 
            return qs.distinct() 
        else: 
            return qs 
 
 
@admin.register(Book) 
class AdminBookstore(admin.ModelAdmin): 
    list_display = ('title', 'author', 'description') 
    search_fields = ('title', 'author', 'description') 
    def get_changelist(*a, **k): 
        return MyChangeList