Поиск администратора Django: как переопределить обработчик по умолчанию?

Я хочу настроить способ поиска поисковых запросов в search_fields.

Есть ли способ сделать это без глубокого взлома кода Django или создания полностью независимого представления?

Например, я хотел бы вернуть объединение наборов запросов для каждого из элементов querystring.split(). Таким образом, поиск «apple bar» будет возвращать результаты либо с яблоком, либо с bar, в отличие от поиска по умолчанию, который применяет оператор AND.


person GJ.    schedule 21.08.2010    source источник
comment
Уточните, какого именно поведения вы хотели бы добиться. В идеале привести пример.   -  person Ihor Kaharlichenko    schedule 22.08.2010
comment
Я обновил свой ответ, вы можете прочитать его и отредактировать, а затем попробовать   -  person WeizhongTu    schedule 10.04.2014


Ответы (3)


Это очень легко сделать в django 1.6.

ModelAdmin.get_search_results(запрос, набор запросов, search_term) Новое в Django 1.6.

import operator
# from django.utils.six.moves import reduce  # if Python 3
from django.db.models import Q

class 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
person WeizhongTu    schedule 18.02.2014
comment
В нем есть уязвимость удаленного выполнения кода. Нет необходимости использовать eval для создания объектов Q. - person Gavin Wahl; 04.10.2018
comment
@GavinWahl eval был удален с помощью operator.or_ и reduce, ура! - person WeizhongTu; 11.10.2018

Итак, я использовал код из ответа WeizhongTu и обнаружил в нем не столь очевидную ошибку. Когда мы пытаемся использовать и фильтрацию, и поиск с этим кодом, фильтрация затеняется этой строкой:

queryset = self.model.objects.filter(eval(query_condition))

Важно использовать ТОЛЬКО предыдущие результаты. Таким образом, вы никогда не должны использовать self.model.objects для получения набора запросов, а только фильтровать сам набор запросов. Так:

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
person Dmitry Orlov    schedule 02.11.2017

вы можете добавить метод ModelAdmin:

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

у вас есть запрос здесь, поэтому большая часть материала может зависеть от просмотра, включая параметры URL, файлы cookie, сеансы и т. д.

person Jerzyk    schedule 25.03.2011