我正在使用django 1.8。 我需要的是在多个字段中执行不区分大小写的 admin-search ,并允许用户使用AND,OR和NOT运算符以及一些组字如何用括号或引号。 搜索示例:
棉和(红色或"深蓝色")
我已经发现了django-advanced-filter和django-filter ...... 他们是过滤器!我还想让用户在搜索框中输入密钥。 我知道 get_search_results 允许我们覆盖搜索行为,但在我为此编写代码之前,我想问一下是否有一个包可以为我做这个? 请注意,我觉得使用haystack进行自定义搜索非常复杂。
答案 0 :(得分:3)
在执行评论中提到的小编辑后,此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