Django如何循环渲染无限层级的嵌套列表?
解决无限层级嵌套列表的修改方案
一、修改查询逻辑(视图层)
核心是建立父项与子项的映射关系,而非分开传递顶级和所有子项:
先查询所有Item数据,按「父项ID」分组构建字典(如
child_map),键为父项ID,值为对应直接子项列表。假设你的Hierarchy模型通过parent和child外键关联Item,代码示例:from django.shortcuts import render from .models import Item def item_list(request): all_items = Item.objects.all() child_map = {} for item in all_items: # 根据你的模型关联逻辑获取父项ID,这里假设Item有parent_id字段 parent_id = item.parent_id if hasattr(item, 'parent_id') else item.hierarchy.parent.id if parent_id not in child_map: child_map[parent_id] = [] child_map[parent_id].append(item) top_level_items = Item.objects.filter(toplevel=True) return render(request, 'item_list.html', { 'top_level_items': top_level_items, 'child_map': child_map })若使用Django 3.2+,也可通过
Prefetch预加载子项,但字典映射方式更直观,适配任意深度层级。
二、修改模板循环(模板层)
采用递归渲染逻辑,让每个项渲染完成后,自动调用相同逻辑渲染其子项:
创建可复用的递归模板片段(如
_item_recursive.html):{% for item in items %} <li> {{ item.name }} <!-- 检查当前项是否存在子项 --> {% if child_map.get(item.id) %} <ul> <!-- 递归调用模板片段,传入当前项的子列表 --> {% include "_item_recursive.html" with items=child_map.get(item.id) %} </ul> {% endif %} </li> {% endfor %}在主模板(
item_list.html)中引入该片段,传入顶级Item:<ul> {% include "_item_recursive.html" with items=top_level_items %} </ul>
三、额外优化(可选)
若层级极深或数据量大,可使用数据库递归查询(如PostgreSQL的WITH RECURSIVE)一次性获取完整层级结构,减少模板层遍历开销:
from django.db import connection def get_hierarchy_items(): with connection.cursor() as cursor: cursor.execute(""" WITH RECURSIVE item_hierarchy AS ( SELECT id, name, parent_id, 1 as level FROM yourapp_item WHERE toplevel = TRUE UNION ALL SELECT i.id, i.name, i.parent_id, ih.level + 1 FROM yourapp_item i JOIN item_hierarchy ih ON i.parent_id = ih.id ) SELECT * FROM item_hierarchy ORDER BY level, id; """) columns = [col[0] for col in cursor.description] return [dict(zip(columns, row)) for row in cursor.fetchall()]
内容的提问来源于stack exchange,提问作者vaemps
相关产品推荐
相关产品推荐

