日常的开发过程中我们需要经常与“树”打交道,例如公司的组织架构树、服务器的项目归属树,管理后台侧边树等等,本篇文章介绍关于树的两个内容
zTree
zTree是一个开源的依靠JQuery实现的多功能树插件,具有性能优异、配置灵活、功能强大的特点
之前的已经多次介绍过将前端插件引入自己项目中的方法,这里就不赘述了,如有问题也可以参考文章末尾给出的Demo代码,在引入JS/CSS之后只需要如下代码即可构建一颗树
<ul id="treeDemo" class="ztree"></ul>
<script>
    var setting = {
      data: {
        simpleData: {
          enable: true
        }
      }
    };
    var zNodes = [
      {id: 1, pId: 0, name: "OPS-COFFEE ", open: true},
      {id: 2, pId: 1, name: "运营部", open: true},
      {id: 3, pId: 1, name: "市场部", open: true},
      {id: 4, pId: 1, name: "综合部", open: true},
      {id: 5, pId: 2, name: "产品部", open: true},
      {id: 6, pId: 2, name: "技术部", open: true},
      {id: 7, pId: 3, name: "销售部", open: true},
      {id: 8, pId: 4, name: "人事部", open: true},
      {id: 9, pId: 4, name: "财务部", open: true},
    ];
    $.fn.zTree.init($("#treeDemo"), setting, zNodes);
</script>$.fn.zTree.init初始化树,这里需要三个参数,第一个参数是加载树结构的Jquery对象,setting为ztree的各种配置参数,zNodes为ztree的具体数据
zTree的配置采用json的格式,按照配置类型分为了界面配置view,数据配置data,编辑配置edit,复选框配置check,异步加载配置async以及各种回调函数配置callback,配置丰富且强大
zTree支持两种数据模式,简单数据模式和标准数据模式,简单数据模式就像我们上边例子中这样的数据结构,而标准数据模式就需要将数据构造成复杂的JSON嵌套格式,像下边这样
var zNodes = [{
  "name": "OPS-COFFEE",
  "open": true,
  "children": [
      {
          "name": "运营部",
          "open": true,
          "children": [
              {"name": "产品部","open": true},
              {"name": "技术部","open": true}
          ]
      },
      {
          "name": "市场部",
          "open": true,
          "children": [
              {"name": "销售部","open": true}
          ]
      },
      {
          "name": "综合部",
          "open": true,
          "children": [
              {"name": "人事部","open": true},
              {"name": "财务部","open": true}
          ]
      }
  ]
}];标准模式数据结构复杂但父子关系清晰,简单模式数据则相反,示例中我们使用了简单数据模式,需要配置simpleData的enable属性为true
完成以上配置后可以看到页面效果如下
Django
既然前端页面已经能够正常展示树了,后端就只需要返回前端对应的数据格式即可,Django中最简单的方式就是使用Foreignkey的自关联,模型设计如下:
class Department(models.Model):
    name = models.CharField(
        max_length=128, unique=True, verbose_name='名称')
    parent = models.ForeignKey(
        'self', on_delete=models.PROTECT, db_constraint=False,
        null=True, blank=True, verbose_name='父部门')ForeignKey第一个参数用self就表示自关联,自己关联自己,还有两个Foreignkey的重要参数解释如下:
on_delete: 控制当外键引用的对象被删除时指定的SQL约束行为
- CASCADE:级联删除,当你删除数据时与之关联的也会删除
- PROTECT:保护模式,当你删除数据时会抛出ProtectedError的错误
- SET_NULL:设置为空,当你删除数据时外键字段被设置为空,前提是有设置null=True, blank=True
- SET_DEFAULT:设置默认值,当你删除数据时外键字段设置为默认值,前提是有设置default值
- DO_NOTHING:什么也不做,但这可能会导致你在调用数据时报错
- SET:设置一个指定的自定义实例,官方案例如下
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )这个案例的意思是当删除外键字段user有关联时调用get_sentinel_user方法,这个方法会返回一个username为deleted的实例
db_constraint: 控制是否在数据库中为此外键创建约束,默认为True。在数据库中创建外键约束是数据库规范中明令禁止的行为,那么我们可以设置db_constraint为False从而不在数据库层面创建约束,但同样可以使用Django为Foreignkey提供的各种关联查询
接下来可以通过如下代码将数据库中的数据转成ztree所能使用的简单模式数据并返回
def tree(request):
    mList = Department.objects.all()
    _data = [
        {
            'id': x.id,
            'name': x.name,
            'pId': x.parent.id if x.parent else 0, 'open': 1
        } for x in mList
    ]
    return render(request, 'tree.html', {'data': _data})注意在前端使用时需要用{{data|safe}}的方式,添加|safe主要是因为Django为了安全默认会对HTML、JS等语法标签进行转义,但我们所传给前端的数据不希望转义可以通过添加|safe来实现
完整Demo
相关文章推荐阅读:
