Как отфильтровать результаты ModelAdmin autocomplete_fields из клиентского ввода - PullRequest
0 голосов
/ 28 апреля 2020

Это продолжение в этой теме: Как фильтровать результаты ModelAdmin autocomplete_fields с контекстом limit_choices_to

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

Form

Мне удалось установить флажок для виджета, переопределив виджет AutocompleteSelect следующим образом:

class AutocompleteSelectCb(AutocompleteSelect):
def render(self, name, value, attrs=None):
    s = super().render(name, value, attrs)
    return mark_safe('<div style="margin-bottom:10px;"><input type="checkbox" id="parent1"\
         name="parentx" value="1">Search among all kennels</div>' + s)

и использовать этот виджет только тогда, когда поля присутствуют в атрибуте autocomplete_cb_fields администратора:

 autocomplete_fields = ['breed']
 autocomplete_cb_fields = ['father', 'mother']

Однако я не уверен, как заставить мой виджет AutocompleteSelectCb отправлять статус флажка, чтобы он мог обрабатываться в методе get_search_results. Я предполагаю с некоторыми js, но как? Есть идеи?

1 Ответ

0 голосов
/ 30 апреля 2020

Я наконец-то смог решить проблему, используя подход, изложенный в этом посте, который добавляет ключи строки запроса к URL-адресу реферера, поскольку select2 не принимает изменение URL-адреса запроса после инициализации. Я также добавляю другую информацию о редактируемой собаке, такую ​​как ее идентификатор и год рождения, для дальнейшей фильтрации набора запросов (собака не может быть собственным родителем или иметь родителя моложе себя, а матери могут быть только самками ...).

//this get passes to the select2:opening event listener
function expand_ajax_location_search($, fieldId) {
    if (!$) {
        $ = django.jQuery;
    }
    var pageURL = $(location).attr("href");
    var match = pageURL.match(/\/.*\/(\d+)\/change/);
    return `&birth_year=${$('#id_birth_year').val()}&dog_id=${match[1]}&father_cb=${$('#father-cb').prop( "checked" )}&mother_cb=${$('#mother-cb').prop( "checked" )}`
}

Наконец, фильтрация на стороне сервера была сложной задачей, потому что администратор собаки обычно фильтруется по питомнику, так что каждый владелец питомника может редактировать только своих собак, хотя флажок позволяет им использовать собак других питомников в качестве родители. Задача метода get_search_results состояла в том, чтобы отфильтровать набор запросов, когда флажок установлен, что невозможно сделать, поэтому создайте новый до , передав его в super (). Get_search_results. Также кажется, что базовый метод get_search_results пересекает все отношения, даже если они не нужны, что приводит к более чем 100 запросам, поэтому использование select_related для всех отношений приводит только к одному запросу.

def get_search_results(self, request, queryset, search_term):
    if request.is_ajax and '/autocomplete/' in request.path and request.GET.get('model_name') == 'dog':
        url = urllib.parse.urlparse(request.headers['Referer'])
        referer = url.path
        # (parse_qs results are lists)
        qs = urllib.parse.parse_qs(url.query)
        if request.GET.get('field_name') == 'father':
            if qs.get('father_cb')[0] == 'true':
                # default is filetered by kennel so need new qs
                queryset = Dog.objects.select_related(
                    'kenn', 'img', 'father', 'mother', 'breeder').order_by('name')
            queryset, use_distinct = super().get_search_results(request, queryset, search_term)
            queryset = queryset.exclude(
                sex='F').exclude(id=qs.get('dog_id')[0])
        elif request.GET.get('field_name') == 'mother':
            if qs.get('mother_cb')[0] == 'true':
                # default is filetered by kennel so need new qs
                queryset = Dog.objects.select_related(
                    'kenn', 'img', 'father', 'mother', 'breeder').order_by('name')
            queryset, use_distinct = super().get_search_results(request, queryset, search_term)
            queryset = queryset.exclude(
                sex='M').exclude(id=qs.get('dog_id')[0])
        birth_year = qs.get('birth_year')[0]
        if birth_year:
            queryset = queryset.exclude(birth_year__gt=birth_year)
    else:
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
    return queryset, use_distinct
...