如何用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
相关产品推荐
相关产品推荐

