Django应用-6-实现树状目录

在搭建知识体系内容页的时候,希望在页面左侧展示出树状结构的知识体系目录。本文介绍两种实现树状目录的方式,推荐使用bootstrap tree view组件。

1、手动实现树状目录

通过django引用的treebeard库内的get_annotated_list()方法,获取树状结构,然后在模板内通过for循环实现树的嵌套结构。

get_annotated_list方法的实现逻辑是:

如果源数据结构如下:

source data

方法将会返回:

[
    (a,     {'open':True,  'close':[],    'level': 0})
    (ab,    {'open':True,  'close':[],    'level': 1})
    (aba,   {'open':True,  'close':[],    'level': 2})
    (abb,   {'open':False, 'close':[],    'level': 2})
    (abc,   {'open':False, 'close':[0,1], 'level': 2})
    (ac,    {'open':False, 'close':[0],   'level': 1})
]

在返回值中,open表示是否要新建一层树叶;close表示是否要结束这一层,返回上一层;level表示当前节点是在树的第几层。

在我的项目中,具体实现方法如下所示:

model.py:

# 数学根节点:
math_subject_root = SubjectClassification.objects.specific().filter(depth=5)[0]
annotate_list = self.get_annotated_list(parent=math_subject_root)

template.html:

<div class="treeview w-20 border">
    <h6 class="pl-3 pt-3">知识结构</h6>
    <hr>
    {% for item, info in annotate_list %}
        {% if info.open %}
            <ul><li>
        {% else %}
            </li><li>
        {% endif %}
        {{ item }}
        {% for close in info.close %}
            </li></ul>
        {% endfor %}
    {% endfor %}
</div>

2、通过bootstrap tree view实现

在方法1中,需要自己写样式以及js的交互,处理层级的展开及收起,非常麻烦。可以使用bootstrap现成的组件:boottstrap tree view。

Step1、在template内引用tree view:

<!-- Required Stylesheets -->
<link href="bootstrap.css" rel="stylesheet">

<!-- Required Javascript -->
<script src="jquery.js"></script>
<script src="bootstrap-treeview.js"></script>

<script>
    var json_string = '{{ tree|escapejs }}'; //获取json字符串对象并转义
    var json_object = JSON.parse(json_string); //解析json字符串对象得到JavaScript json对象
    $('#tree').treeview({
        data: json_object,
        levels: 5,
        enableLinks: true,
    });
</script>

Step2、在template内放入DOM元素,js脚本将会作用在此DOM内

<div id="tree"></div>

Step3、在model内写源数据的逻辑

# 数学根节点:
math_subject_root = SubjectClassification.objects.specific().filter(depth=5)[0]
annotate_list = self.get_annotated_list(parent=math_subject_root)

        # 产出treeview需要的内容
        tree = []
        for item, info in annotate_list:
            item_info = {
                'text': item.title,
                'href': item.url,
                'nodes': [],
                'state': {
                    'expanded': False
                }
            }
            # 如果这个节点是自己
            if item.id == self.id:
                item_info['state'] = {
                    'selected': True,
                    'expanded': True
                }
            # 如果这个节点是自己的父级
            if self.is_descendant_of(item):
                item_info['state'] = {
                    'expanded': True
                }
            if info['level'] == 1:
                tree.append(item_info)
            elif info['level'] == 2:
                tree[-1]['nodes'].append(item_info)
            elif info['level'] == 3:
                tree[-1]['nodes'][-1]['nodes'].append(item_info)
            elif info['level'] == 4:
                tree[-1]['nodes'][-1]['nodes'][-1]['nodes'].append(item_info)

最终实现效果如下:

最终实现效果

参考链接:

treebeard文档:https://django-treebeard.readthedocs.io/en/latest/api.html

bootstrap tree view文档:https://github.com/jonmiles/bootstrap-treeview

Leave a comment

Your email address will not be published. Required fields are marked *