You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django ListView中实现无刷新多规则排序并获取对应QuerySet?

问题背景

现有以下Django代码,需实现商品按名称正倒序、价格升降序、折扣优先的排序功能,且要求无刷新页面更新商品列表:

# view.py
class HomeView(ListView):
    model = Item
    template_name = "home.html"
    paginate_by = 12
<!-- 模板代码 -->
<div class="header-dropdown">
    <a href="#">A to Z</a>
    <div class="header-menu">
        <ul>
            <li><a href="#">A to Z</a></li>
            <li><a href="#">Z to A</a></li>
            <li><a href="#">Discount</a></li>
            <li><a href="#">Low to high price</a></li>
            <li><a href="#">High to low price</a></li>
        </ul>
    </div>
</div>

实现方案

1. 后端调整:处理排序参数与AJAX请求

修改HomeView,通过get_queryset根据请求参数返回对应排序的QuerySet,并支持AJAX请求返回商品列表片段:

# view.py
from django.http import JsonResponse
from django.template.loader import render_to_string
from django.views.generic import ListView
from .models import Item

class HomeView(ListView):
    model = Item
    template_name = "home.html"
    paginate_by = 12

    def get_queryset(self):
        queryset = super().get_queryset()
        sort_option = self.request.GET.get('sort')
        # 排序规则映射(需与Item模型字段对应)
        sort_mapping = {
            'az': 'name',               # 名称A-Z
            'za': '-name',              # 名称Z-A
            'discount': '-discount',    # 折扣优先(假设Item有discount字段)
            'low_high': 'price',        # 价格从低到高
            'high_low': '-price'        # 价格从高到低
        }
        if sort_option in sort_mapping:
            queryset = queryset.order_by(sort_mapping[sort_option])
        return queryset

    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        context = self.get_context_data()
        # 识别AJAX请求,返回商品列表片段
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            html = render_to_string('item_list_fragment.html', context)
            return JsonResponse({'html': html})
        return super().get(request, *args, **kwargs)

2. 模板拆分与修改

  • 抽离商品列表为单独的片段模板item_list_fragment.html:
<!-- item_list_fragment.html -->
{% for item in object_list %}
    <div class="item-card">
        <h3>{{ item.name }}</h3>
        <p>价格:{{ item.price }}</p>
        {% if item.discount %}
            <p>折扣价:{{ item.discount_price }}</p>
        {% endif %}
    </div>
{% empty %}
    <p>暂无商品</p>
{% endfor %}

<!-- 保留分页控件(可选,后续可扩展AJAX分页) -->
{% if is_paginated %}
    <div class="pagination">
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}&sort={{ request.GET.sort }}">上一页</a>
        {% endif %}
        <span>第 {{ page_obj.number }} 页 / 共 {{ page_obj.paginator.num_pages }} 页</span>
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}&sort={{ request.GET.sort }}">下一页</a>
        {% endif %}
    </div>
{% endif %}
  • 修改主模板home.html,添加排序链接的标识属性,引入商品列表容器:
<!-- home.html 排序下拉部分 -->
<div class="header-dropdown">
    <a href="#">排序选项</a>
    <div class="header-menu">
        <ul>
            <li><a href="#" data-sort="az">A to Z</a></li>
            <li><a href="#" data-sort="za">Z to A</a></li>
            <li><a href="#" data-sort="discount">Discount</a></li>
            <li><a href="#" data-sort="low_high">Low to high price</a></li>
            <li><a href="#" data-sort="high_low">High to low price</a></li>
        </ul>
    </div>
</div>

<!-- 商品列表容器 -->
<div id="item-list-container">
    {% include 'item_list_fragment.html' %}
</div>

3. 前端AJAX实现无刷新排序

在模板底部添加JavaScript,监听排序链接点击事件,发送AJAX请求并更新页面:

<script>
document.querySelectorAll('.header-menu a[data-sort]').forEach(link => {
    link.addEventListener('click', function(e) {
        e.preventDefault();
        const sortOption = this.getAttribute('data-sort');
        const url = new URL(window.location.href);
        url.searchParams.set('sort', sortOption);

        // 发送AJAX请求
        fetch(url, {
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        })
        .then(response => response.json())
        .then(data => {
            // 更新商品列表
            document.getElementById('item-list-container').innerHTML = data.html;
            // 更新地址栏URL(保留排序参数,支持刷新)
            window.history.pushState({}, '', url);
        })
        .catch(error => console.error('排序请求失败:', error));
    });
});
</script>

关键说明

  • 排序映射表需根据Item模型的实际字段调整,确保字段存在且可排序。
  • AJAX请求通过X-Requested-With头与普通请求区分,后端返回片段HTML而非完整页面。
  • 使用history.pushState更新地址栏,保证用户刷新页面后仍保留当前排序状态。

内容的提问来源于stack exchange,提问作者Adebola Ajewole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:31:19