Django admin search: how to override the default handler?
It is very easy to do this in django 1.6
ModelAdmin.get_search_results(request, queryset, search_term) New in Django 1.6.
import operator# from django.utils.six.moves import reduce # if Python 3from django.db.models import Qclass PersonAdmin(admin.ModelAdmin): list_display = ('name', 'age') search_fields = ('name',) def get_search_results(self, request, queryset, search_term): # search_term is what you input in admin site # queryset is search results queryset, use_distinct = super(PersonAdmin, self).get_search_results(request, queryset, search_term) search_term_list = search_term.split(' ')#['apple','bar'] # you can also use `self.search_fields` instead of following `search_columns` search_columns = ('name','age','address') #convert to Q(name='apple') | Q(name='bar') | Q(age='apple') | ... query_condition = reduce(operator.or_, [Q(**{c:v}) for c in search_columns for v in search_term_list]) queryset = self.model.objects.filter(query_condition) # NOTICE, if you want to use the query before # queryset = queryset.filter(query_condition) return queryset, use_distinct
So I have been using the code from WeizhongTu's answer and found a not-so-obvious error in it. When we try to use both filtering and searching with this code, filtering is shadowed by this line:
queryset = self.model.objects.filter(eval(query_condition))
It is important to use the previous results ONLY. So you must never use self.model.objects
to obtain the queryset, but only filter the queryset itself. Like this:
def get_search_results(self, request, queryset, search_term): # search_term is what you input in admin site # queryset is the list of objects passed to you # by the previous functions, e. g. filtering search_term_list = search_term.split(' ') #['apple','bar'] search_columns = ('name','age','address') # convert to Q(name='apple') | Q(name='bar') | Q(age='apple') | ... query_condition = ' | '.join(['Q(%s="%s")'%(x,y) for x in search_term_list for y in search_columns]) appended_queryset = queryset.filter(eval(query_condition)) # queryset is search results queryset, use_distinct = super(PersonAdmin, self).get_search_results(request, queryset, search_term) queryset |= appended_queryset return queryset, use_distinct
you can add an ModelAdmin
method:
def queryset(self, request): qs = super(MyModelAdmin, self).queryset(request) # modify queryset here, eg. only user-assigned tasks qs.filter(assigned__exact=request.user) return qs
you have a request here, so most of the stuff can be view dependent, including url parameters, cookies, sessions etc.