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

如何用Django ListView构建分类导航树并拆分展示?

解决Django ListView按分类展示模型数据的问题

首先,先帮你排查当前代码里的直接问题:你的模板里两个折叠菜单的id都是coll-css!Bootstrap的折叠组件是通过href和id关联的,两个菜单用同一个ID,只会触发第一个,所以第二个Life菜单根本没展开,看起来像是life上下文没数据,但其实是菜单没显示出来而已。

先修正模板里的ID:

<ul class="sidebar-nav animated fadeIn">
    <li>
        <a data-toggle="collapse" href="#coll-health" class="collapsed"><i class="fa fa-heart"></i> Health</a>
        <ul id="coll-health" class="menu-submenu list-unstyled collapse">
            {% for service in health %}
                <li><a href="{% url 'services' %}{{ service.slug }}"><i class="fa {{ service.icon }}"></i>{{ service.title }}</a></li>
            {% endfor %}
        </ul>
        <a data-toggle="collapse" href="#coll-life" class="collapsed"><i class="fa fa-heart"></i> Life</a>
        <ul id="coll-life" class="menu-submenu list-unstyled collapse">
            {% for service in life %}
                <li><a href="{% url 'services' %}{{ service.slug }}"><i class="fa {{ service.icon }}"></i>{{ service.title }}</a></li>
            {% endfor %}
        </ul>
    </li>
</ul>

把第一个折叠菜单的href和id改成coll-health,第二个改成coll-life,这样两个菜单就能正常展开,你应该就能看到life上下文的内容了。另外,模板完全支持多个for循环,这一点不用担心。


更优的实现方案(避免硬编码分类)

你当前的视图是硬编码了health和life两个分类,以后如果新增其他分类,每次都要修改视图和模板,非常麻烦。可以改成动态获取所有分类,这样扩展性更好:

1. 修改views.py

from django.db.models import Value
from django.db.models.functions import Lower

class ServiceView(ListView):
    model = Service
    template_name = "services/services.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 获取所有不重复的service_type(忽略大小写,避免重复)
        service_types = Service.objects.values_list(Lower('service_type'), flat=True).distinct()
        # 把每个分类对应的服务存入上下文,用小写的分类名作为键
        for service_type in service_types:
            context[service_type] = Service.objects.filter(service_type__iexact=service_type)
        # 也可以把分类列表单独存起来,方便模板遍历
        context['service_types'] = [type.title() for type in service_types]
        return context

2. 修改模板(动态渲染所有分类)

<ul class="sidebar-nav animated fadeIn">
    <li>
        {% for type in service_types %}
            {% with lower_type=type.lower %}
                <a data-toggle="collapse" href="#coll-{{ lower_type }}" class="collapsed">
                    <i class="fa fa-heart"></i> {{ type }}
                </a>
                <ul id="coll-{{ lower_type }}" class="menu-submenu list-unstyled collapse">
                    {% for service in lower_type %}
                        <li><a href="{% url 'services' %}{{ service.slug }}">
                            <i class="fa {{ service.icon }}"></i>{{ service.title }}
                        </a></li>
                    {% endfor %}
                </ul>
            {% endwith %}
        {% endfor %}
    </li>
</ul>

这样不管以后新增多少个服务分类,视图和模板都不用修改,自动就能渲染出对应的菜单。另外,注意把filter里的icontains改成iexact,避免匹配到包含该关键词的其他分类(比如如果有个分类叫healthcare,icontains='health'也会匹配到,iexact只会精确匹配)。

内容的提问来源于stack exchange,提问作者John Marcus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:41:44