如何使用Django与HTMX实现queryset排序?现有代码失效如何解决
问题原因&修复方案
现有代码的错误点
- 视图逻辑错误1:参数取值异常。代码中
qs= request.GET['order_by']已经拿到了order_by参数的字符串值,后续print('request', qs['order_by'])尝试将字符串作为字典取值,会直接抛出KeyError导致接口报错。同时直接用request.GET['键名']方式取值,参数不存在时会直接抛出异常,没有做缺省兼容。 - 视图逻辑错误2:过滤、排序顺序颠倒。需求是先通过django-filter拿到过滤结果,再对过滤结果排序,现有代码是先对全量产品排序,再将排序后的全量结果交给django-filter过滤,逻辑完全不符。
- 前端事件触发失效:你给select标签加了
nice-select类,这是常用的下拉美化插件,它会隐藏原生select元素、生成自定义DOM结构,原生select的change事件不会被触发,HTMX绑定的触发规则自然失效。 - 过滤参数丢失:当前排序表单只会提交order_by参数,不会携带用户之前输入的django-filter筛选参数,排序后之前的筛选结果会丢失。
修复代码
视图代码修正
def sorted_htmx_products(request): context = {} # 第一步:先执行django-filter过滤,拿到过滤后的数据集 product_filter = ProductFilter(request.GET, queryset=Product.objects.all()) filtered_qs = product_filter.qs # 第二步:对过滤后的数据集排序,用get方式取值兼容参数缺省场景 order_by = request.GET.get('order_by', 'default') order_map = { "name_a": "name", "name_z": "-name", "price": "price", "brand": "brand" } if order_by in order_map: filtered_qs = filtered_qs.order_by(order_map[order_by]) context['products'] = filtered_qs return render(request, 'snippets/htmx_products.html', context)
前端代码修正
首先确认你的django-filter筛选表单的id为filter-form(如果id不同自行替换),修正后的排序表单代码如下:
<div class="product-select-box"> <div class="product-short" > <!-- hx-include属性会把指定id的表单所有参数一起提交,保留筛选条件 --> <form hx-get="{% url 'core:sorted-products' %}" hx-target="#removed-products" hx-swap="outerHTML"> <p>Trier par:</p> <select name="order_by" class="nice-select" > <option value="default">Default</option> <option value="name_a">Nom (A - Z)</option> <option value="name_z">Nom (Z - A)</option> <option value="price">Prix</option> <option value="brand">Marque</option> </select> </form> </div> </div> <!-- 兼容nice-select插件的事件触发脚本 --> <script> $('.nice-select').on('change', function() { // 手动触发当前select所在表单的HTMX提交 $(this).closest('form').trigger('submit'); }); </script>
如果不需要使用nice-select美化下拉框,直接删除select标签的class="nice-select"属性即可,原生select的change事件可以被HTMX正常识别,不需要额外加脚本。
内容的提问来源于stack exchange,提问作者miyou995
相关产品推荐
相关产品推荐

