【问题标题】:How to filter ModelAdmin autocomplete_fields results from clientside input如何从客户端输入过滤 ModelAdmin autocomplete_fields 结果
【发布时间】:2020-08-11 14:26:57
【问题描述】:

这是对该线程的后续跟进: How to filter ModelAdmin autocomplete_fields results with the context of limit_choices_to

Uberdude 提出了一个解决方案,该解决方案非常适合根据触发请求的字段自定义自动选择查询集,但我还需要根据来自客户端的输入进行过滤,尤其是不是模型字段的复选框,并且仅适用于表单中的某些字段,如本表单摘录。

我设法通过覆盖您的 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,但是如何?有什么想法吗?

【问题讨论】:

    标签: python django django-admin


    【解决方案1】:

    我终于能够通过使用this 帖子中列出的方法解决问题,即将查询字符串键添加到引用 URL,因为 select2 在初始化后不接受对请求 URL 的修改。 我还添加了有关正在编辑的狗的其他信息,例如它的 id 和出生年份,以进一步过滤查询集(狗不能是它自己的父母或比自己年轻的父母,母亲只能是女性......)。

    //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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-25
      • 2021-10-15
      • 1970-01-01
      • 2016-02-27
      • 1970-01-01
      相关资源
      最近更新 更多