1、使用Django自带的标签 unordered_list
1.1、定义模型
class Department(models.Model):
name = models.CharField(max_length=64, unique=True, verbose_name="部门名称")
# db_constraint 控制是否在数据库中为此外键创建约束,默认为True。在数据库中创建外键约束是数据库规范中明令禁止的行为
# 但是不影响Django的关联查询
parent = models.ForeignKey('Department',
on_delete=models.PROTECT,
null=True, blank=True,
db_constraint=False,
related_name='children',
verbose_name="父级部门")
def __str__(self):
return self.name
1.2、自定义递归获取函数和view
from app.models import Department
def recurse_display(data):
"""递归展示"""
display_list = []
for item in data:
display_list.append(item.name)
children = item.children.all()
if len(children) > 0:
display_list.append(recurse_display(children))
return display_list
def depart_tree(request):
# 核心是filter(parent=None) 查到最顶层的那个parent节点
departs = Department.objects.filter(parent=None)
data = recurse_display(departs)
return render(request, 'app/tree.html', {'data': data})
1.3、页面 template中使用
The Tree:
{{ data|unordered_list }}
1.4、效果如下:
1650616476299-3a3cf368-cd81-41b9-a0cf-7f33ff54c733.png2、使用django-mptt
使用前先安装模块
pip install django-mptt
然后需要在 INSTALLED_APPS 中配置上
INSTALLED_APPS = [
... ...
'mptt',
]
2.1、定义模型
from mptt.models import MPTTModel
class DepartMPTT(MPTTModel):
name = models.CharField(max_length=64, unique=True, verbose_name="部门名称")
# db_constraint 控制是否在数据库中为此外键创建约束,默认为True。在数据库中创建外键约束是数据库规范中明令禁止的行为
# 但是不影响Django的关联查询
parent = models.ForeignKey('DepartMPTT',
on_delete=models.PROTECT,
null=True, blank=True,
db_constraint=False,
related_name='children',
verbose_name="父级部门")
# if parent filed name is not parent, e.g. depart_parent
# class MPTTMeta:
# parent_attr = 'depart_parent'
def __str__(self):
return self.name
注意在model中的 MPTTMeta如果父字段使用的不是parent
名称,就需要单独在 MPTTMeta
中说明
2.2、定义view
from app.models import DepartMPTT
def depart_mptt_tree(request):
departs = DepartMPTT.objects.all()
return render(request, 'app/mptt.html', {'departs': departs})
这里网上有些文章说必须在context中使用nodes
才可以,即 {'nodes': departs}
;其实进过验证不必非得是nodes才行,比如这里的 departs
2.3、在template中使用
<!-- 首先要导入对应的标签 -->
{% load mptt_tags %}
{% recursetree departs %}
<li>
<!-- 这里可以使用with把node赋值给其他的变量名 -->
{% if node.is_leaf_node %}
<span style="color: orange;">{{ node.name }}</span>
{% else %}
<span style="color: red;">{{ node.name }}</span>
<ul>
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
这里需要注意的是,在前端代码中node有时候有特殊含义,可以使用 with 标签进行替换,注意标记要闭合结束 {% endwith %}
2.4、扩展admin
mptt提供了对应的admin类,在后台添加和展示 MTPPModel 的时候会更友好些
from .models import DepartMPTT
from mptt.admin import MPTTModelAdmin
admin.site.register(DepartMPTT, MPTTModelAdmin)
具体效果就不给大家展示,可以自己尝试下
最终效果和上面第一种方式的效果类似。
3、项目代码
具体的源码和使用说明详见 https://gitee.com/colin5063/django_learning/tree/django_tree/