如何将层级字典列表转换为HTML多级下拉菜单?
多级HTML下拉菜单生成问题
现有一个层级可扩展的字典列表WIDGETS,需要将其转换为符合Bootstrap样式的多级下拉菜单HTML结构。尝试了递归函数但未正常工作,以下是问题详情及修正方案:
原始数据
WIDGETS = [ {"id": 1, "pid": 0, "url": "/upload"}, {"id": 2, "pid": 0, "url": "/entry"}, {"id": 3, "pid": 0, "url": "/report"}, {"id": 4, "pid": 3, "url": "/reppremium"}, {"id": 5, "pid": 4, "url": "/reppremiumsum"}, {"id": 6, "pid": 4, "url": "/reppremiumfull"}, {"id": 7, "pid": 3, "url": "/repcommission"}, {"id": 8, "pid": 7, "url": "/repcommissionsum"}, {"id": 9, "pid": 7, "url": "/repcommissionfull"}, {"id": 10, "pid": 3, "url": "/repportions"}, {"id": 11, "pid": 10, "url": "/repportionssum"}, {"id": 12, "pid": 10, "url": "/repportionsfull"}, {"id": 13, "pid": 0, "url": "/adduser"}, {"id": 14, "pid": 0, "url": "/exportdb"}, {"id": 15, "pid": 0, "url": "/importdb"}, ]
期望的菜单结构
main menu -> /upload /report -> /reppremium -> /reppremiumsum -> /reppremiumfull -> /repcommission -> /repcommissionsum -> /repcommissionfull -> /repportions -> /repportionssum -> /repportionsfull /adduser /exportdb /importdb
原错误代码
def get_widgets(widgets,text='',pid=0,text_m=''): childs = get_childs(pid,widgets) for child in childs: pidn = child['id'] n = get_childs(pidn,widgets) print(n,'for id',pidn) if len(n) != 0: text += f''' <li class="nav-item dropend"> <a class="nav-link dropdown-toggle" href="{ child['url'] }" role="button" data-bs-toggle="dropdown" aria-expanded="false"> { child['url'] } </a> <ul class="dropdown-menu nav nav-pills flex-column mb-sm-auto mb-0 align-items-center align-items-sm-start"> ''' pid_new = child['id'] get_widgets(widgets,text,pid_new) text += '</ul></li>' print(text) text_m += text else: #print(n,'n') text += f''' <li class="nav-item"> <a class="nav-link dropdown-item" href="{ child['url'] }">{ child['url'] }</a> </li> ''' text_m += text text = '' return tex
问题分析
- 递归调用未接收返回的HTML片段,导致子菜单内容丢失
text和text_m变量管理混乱,循环内重置text会丢失部分内容- 函数返回值拼写错误(
tex应为text_m) - 缺少
get_childs实现,且每次递归遍历全量数据效率低下
修正方案
步骤1:预分组子节点优化结构
先按pid分组所有节点,避免重复遍历:
from collections import defaultdict def build_widget_tree(widgets): tree = defaultdict(list) for widget in widgets: tree[widget['pid']].append(widget) return tree
步骤2:重写递归生成函数
修正变量逻辑,正确拼接子菜单内容:
def generate_menu_html(widget_tree, pid=0): html_fragments = [] for widget in widget_tree[pid]: children = widget_tree[widget['id']] if children: # 生成带下拉的父节点 html_fragments.append(f''' <li class="nav-item dropend"> <a class="nav-link dropdown-toggle" href="{widget['url']}" role="button" data-bs-toggle="dropdown" aria-expanded="false"> {widget['url']} </a> <ul class="dropdown-menu"> {generate_menu_html(widget_tree, widget['id'])} </ul> </li> ''') else: # 生成普通菜单项 html_fragments.append(f''' <li class="nav-item"> <a class="nav-link dropdown-item" href="{widget['url']}">{widget['url']}</a> </li> ''') return '\n'.join(html_fragments).strip()
步骤3:完整调用示例
# 构建树结构 widget_tree = build_widget_tree(WIDGETS) # 生成完整主菜单HTML main_menu_html = f''' <ul class="nav nav-pills flex-column mb-sm-auto mb-0 align-items-center align-items-sm-start"> {generate_menu_html(widget_tree)} </ul> ''' # 输出或使用生成的HTML print(main_menu_html)
说明
- 生成的HTML适配Bootstrap 5下拉菜单样式,需确保页面已引入Bootstrap的CSS和JS资源
- 预分组的树结构大幅提升递归效率,尤其适用于大数据量场景
- 用列表拼接HTML片段,避免字符串拼接的性能损耗,逻辑更清晰
内容的提问来源于stack exchange,提问作者Alirezadigi
相关产品推荐
相关产品推荐

