将分层字典转换为 HTML 嵌套下拉列表

Convert hierarchical dictionary to HTML nested dropdown

提问人:Alirezadigi 提问时间:1/11/2023 最后编辑:S.BAlirezadigi 更新时间:1/12/2023 访问量:112

问:

我有一个这样的字典列表, 但是我们可能有更多的深度,因此更多的 ID 和 PID ......

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"},
]

我想将其转换为 HTML 嵌套/多级下拉列表,如下所示:

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 多级下拉列表......但由小部件填充......

Python HTML 递归 下拉菜单 嵌套

评论

0赞 ggorlen 1/11/2023
你能显示你对该输入的期望的 HTML 输出吗?
0赞 S.B 1/12/2023
你检查过答案了吗?
0赞 Alirezadigi 1/13/2023
@s.b 是的,亲爱的,现在尝试一下,但它看起来很完美,谢谢,完成部分后标记它!

答:

1赞 S.B 1/12/2023 #1

正如你所猜到的,这应该是递归完成的,有几种方法可以解决它。

以下是完整的代码:

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"},
]


def build_HTML(d, text=""):
    for (id_, url), children_list in d.items():
        text += f"<li>{url}"

        if children_list:
            text += "<ul>"
            for dd in children_list:
                text += build_HTML(dd, "")
            text += "</ul>"

        text += "</li>"

    return text


def set_recursive(obj, d):
    for (id_, url), children_list in d.items():
        if obj["pid"] == id_:
            children_list.append({(obj["id"], obj["url"]): []})
            return
        else:
            for item in children_list:
                set_recursive(obj, item)



root = {(0, "/main-menu"): []}
while WIDGETS:
    d = WIDGETS[0]
    set_recursive(d, root)
    del WIDGETS[0]

print(f"<ul>{build_HTML(root)}</ul>")

输出:

<ul><li>/main-menu<ul><li>/upload</li><li>/entry</li><li>/report<ul><li>/reppremium<ul><li>/reppremiumsum</li><li>/reppremiumfull</li></ul></li><li>/repcommission<ul><li>/repcommissionsum</li><li>/repcommissionfull</li></ul></li><li>/repportions<ul><li>/repportionssum</li><li>/repportionsfull</li></ul></li></ul></li><li>/adduser</li><li>/exportdb</li><li>/importdb</li></ul></li></ul>

解释:

在函数中,我们基本上以以下形式创建另一个数据结构:set_recursive()

{(0, '/main-menu'): [{(1, '/upload'): []},
                     {(2, '/entry'): []},
                     {(3, '/report'): [{(4, '/reppremium'): [{(5, '/reppremiumsum'): []},
                                                             {(6, '/reppremiumfull'): []}]},
                                       {(7, '/repcommission'): [{(8, '/repcommissionsum'): []},
                                                                {(9, '/repcommissionfull'): []}]},
                                       {(10, '/repportions'): [{(11, '/repportionssum'): []},
                                                               {(12, '/repportionsfull'): []}]}]},
                     {(13, '/adduser'): []},
                     {(14, '/exportdb'): []},
                     {(15, '/importdb'): []}]}

现在,这是一本元素字典,可以跟踪每个子元素。它的工作方式是,对于每个元素,它递归地检查数据结构,看看它是否能找到它的“父级”。如果找到,则属于该列表。在我们处理完之后,我们只需将其从记录中删除即可。

在函数中,您以最压缩的形式创建字符串(浏览器的解析器不在乎)。build_HTML()

此功能的要点是您需要在进入之前打开并在之后关闭它。<ul>children_list

注意:此解决方案可以正常工作,因为数据的排序方式是,对于追加每个子项,其父项已追加。

如果呈现该字符串:

<!DOCTYPE html>
<html>

<head>
</head>


<body>

    <ul><li>/main-menu<ul><li>/upload</li><li>/entry</li><li>/report<ul><li>/reppremium<ul><li>/reppremiumsum</li><li>/reppremiumfull</li></ul></li><li>/repcommission<ul><li>/repcommissionsum</li><li>/repcommissionfull</li></ul></li><li>/repportions<ul><li>/repportionssum</li><li>/repportionsfull</li></ul></li></ul></li><li>/adduser</li><li>/exportdb</li><li>/importdb</li></ul></li></ul>

</body>

该字符串的美化版本是:

<ul>
    <li>/main-menu
        <ul>
            <li>/upload</li>
            <li>/entry</li>
            <li>/report<ul>
                    <li>/reppremium
                        <ul>
                            <li>/reppremiumsum</li>
                            <li>/reppremiumfull</li>
                        </ul>
                    </li>
                    <li>/repcommission
                        <ul>
                            <li>/repcommissionsum</li>
                            <li>/repcommissionfull</li>
                        </ul>
                    </li>
                    <li>/repportions
                        <ul>
                            <li>/repportionssum</li>
                            <li>/repportionsfull</li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li>/adduser</li>
            <li>/exportdb</li>
            <li>/importdb</li>
        </ul>
    </li>
</ul>