django 实现:闭包表—树状结构

这篇具有很好参考价值的文章主要介绍了django 实现:闭包表—树状结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

闭包表—树状结构数据的数据库表设计

闭包表模型

闭包表(Closure Table)是一种通过空间换时间的模型,它是用一个专门的关系表(其实这也是我们推荐的归一化方式)来记录树上节点之间的层级关系以及距离。

场景

我们 基于 django orm实现一个文件树,文件夹直接可以实现无限嵌套
django 实现:闭包表—树状结构,django,数据库,sqlite

models

#  文件详情表(主要用于记录文件名)
class DmFileDetail(models.Model):
    file_name = models.CharField("文件名(文件夹名)", max_length=50)
    is_file = models.BooleanField("是否是文件", default=False)
    user_id = models.IntegerField("用户id", default=0)
    create_time = models.IntegerField("创建时间", default=0)
    update_time = models.IntegerField("创建时间", default=0)
    is_del = models.BooleanField("是否删除", default=False)

    class Meta:
        db_table = 'inchat_dm_file_detail'
        verbose_name = verbose_name_plural = u'数字人文件详情表'

    def __str__(self):
        return self.file_name

#  文件关系表(主要用户记录文件之间的关联,即路径)
class DmFileRelation(models.Model):
    ancestor_id = models.IntegerField("祖先节点ID")
    descendant_id = models.IntegerField("子孙节点ID")
    depth = models.IntegerField("深度(层级)", db_index=True)
    user_id = models.IntegerField("用户id", default=0, db_index=True)
    is_del = models.BooleanField("是否删除", default=False)

    class Meta:
        db_table = 'inchat_dm_file_relation'
        index_together = ('ancestor_id', 'descendant_id')
        verbose_name = verbose_name_plural = u'数字人文件关系表'
id file_name
1 AAA
2 aaa.pdf
id ancestor_id descendant_id depth
1 1 1 0
2 2 2 0
3 1 2 1

增删改查

class DmRelationNode:
    """
    关系节点
    """
    NAME = "DmRelationNode"
    RELATION_CLIENT = DmFileRelation

    @classmethod
    def insert_relation_node(cls, node_id, user_id, parent_id):
        """
        插入新的关系节点
        """
        # 自身
        insert_self = cls.RELATION_CLIENT(
            ancestor_id=parent_id,
            descendant_id=node_id,
            user_id=user_id,
            depth=1
        )
        insert_list = []
        # 获取父节点所有祖先
        parent_relation = cls.RELATION_CLIENT.objects.filter(descendant_id=parent_id) \
            .values_list('ancestor_id', 'depth')
        for ancestor_id, depth in parent_relation:
            insert_data = cls.RELATION_CLIENT(
                ancestor_id=ancestor_id,
                descendant_id=node_id,
                depth=depth + 1,
                user_id=user_id
            )
            insert_list.append(insert_data)
        # 插入自身
        insert_list.append(insert_self)
        logger.info('%s insert_relation_node.node_id:%s,parent_id:%s,insert_list:%s', cls.NAME, node_id, parent_id,
                    insert_list)
        ret = cls.RELATION_CLIENT.objects.bulk_create(insert_list)
        logger.info('%s insert_relation_node.node_id:%s,parent_id:%s,ret_list:%s', cls.NAME, node_id, parent_id, ret)
        return ret

    @classmethod
    def get_ancestor_relation(cls, node_id):
        """
        获取某个节点的所有祖先节点
        """
        arges = ['ancestor_id', 'descendant_id', 'depth']
        ancestor_relation_list = cls.RELATION_CLIENT.objects.filter(descendant_id=node_id, is_del=False).values(*arges)
        relation_map = dict()
        relation_dict = relation_map
        for ancestor in ancestor_relation_list:
            relation_dict['id'] = ancestor['ancestor_id']
            if ancestor['ancestor_id'] != node_id:
                relation_dict['children'] = {}
                relation_dict = relation_dict['children']
        return ancestor_relation_list

    @classmethod
    def get_descendant_relation(cls, node_id):
        """
        获取所有的子节点
        """
        arges = ['ancestor_id', 'descendant_id', 'depth']
        descendant_relation_list = cls.RELATION_CLIENT.objects.filter(ancestor_id=node_id, is_del=False).values(*arges)

        return descendant_relation_list

    @classmethod
    def get_direct_relation(cls, user_id):
        """
        获取所有直系
        """
        arges = ['ancestor_id', 'descendant_id', 'depth']
        direct_relation = cls.RELATION_CLIENT.objects.filter(depth=1, user_id=user_id, is_del=False).values(*arges)
        return direct_relation

    @classmethod
    def get_children_node(cls, node_id):
        """
        获取某节点的子节点
        """
        children_node = cls.RELATION_CLIENT.objects.filter(depth=1, ancestor_id=node_id, is_del=False) \
            .values_list('descendant_id', flat=True)
        return children_node

    @classmethod
    def remove_node(cls, node_id):
				"""
        删除节点
        """
        logger.info('%s remove_node. node_id:%s', cls.NAME, node_id)
        query = Q(ancestor_id=node_id, is_del=False) | Q(descendant_id=node_id, is_del=False)
        res = cls.RELATION_CLIENT.objects.filter(query).update(is_del=True)
        logger.info('%s remove_node. node_id:%s,count:%s', cls.NAME, node_id, res)
        return res

以下 是一些常规的操作

class DmFileTree:
    """
    DM文件树
    """
    NAME = "DmFileTree"
    DETAIL_CLIENT = DmFileDetail
    RELATION_NODE_CLIENT = DmRelationNode
    FILE_SAVE_DIR = 'media/dm/'

    @classmethod
    def get_file_map(cls, user_id):
        """
        获取用户所有文件文件名
        """
        file_detail = cls.DETAIL_CLIENT.objects.filter(user_id=user_id).values('id', 'file_name', 'path', 'is_file')
        file_map = dict()
        for file in file_detail:
            file_dict = dict(
                id=file['id'],
                name=file['file_name'],
                is_file=file['is_file'],
                filePath=cls.FILE_SAVE_DIR + file['path'] + file['file_name']
            )
            file_map[file['id']] = file_dict
        return file_map

    @classmethod
    def add_file(cls, user_id, file_name, parent_id, path='', is_file=False):
        """
         新建文件(夹)
        """
        kwargs = dict(
            file_name=file_name,
            path=path,
            is_file=is_file,
            user_id=user_id,
            create_time=get_cur_timestamp()
        )
        file_obj = cls.DETAIL_CLIENT.objects.create(**kwargs)
        if not file_obj:
            logger.error('%s add_file failed. kwargs:%s', cls.NAME, kwargs)
            return False

        res = cls.RELATION_NODE_CLIENT.insert_relation_node(node_id=file_obj.id, user_id=user_id, parent_id=parent_id)
        if not res:
            return False

        return dict(id=file_obj.id, name=file_name)

    @classmethod
    def get_file_path(cls, file_id):
        """
        获取文件路径
        """
        ancestor_query = cls.RELATION_NODE_CLIENT.get_ancestor_relation(file_id)
        ancestor = map(lambda x: x['ancestor_id'], ancestor_query)
        # 过滤0
        ancestor = list(filter(lambda x: x > 0, ancestor))
        # 排序
        ancestor.sort()
        path = '/'.join(map(str, ancestor))
        return '/' + path + '/' if path else '/'

    @classmethod
    def get_all_files(cls, user_id):
        # 获取所有文件名字典
        file_map = cls.get_file_map(user_id)
        # 查询所有子目录及文件
        files_relation_list = cls.RELATION_NODE_CLIENT.get_direct_relation(user_id)
        file_info = {a['descendant_id']: file_map.get(a['descendant_id']) or {} for a in files_relation_list}
        tree = cls.list_to_tree(files_relation_list, file_info)
        return tree

    @classmethod
    def get_child_files(cls, user_id, parent_id):
        """
        获取下级文件
        """
        # 获取所有文件名字典
        file_map = cls.get_file_map(user_id)
        file_list = cls.RELATION_NODE_CLIENT.get_children_node(node_id=parent_id)

        files = map(lambda x: dict(id=x, name=file_map.get(x) or ''), file_list)
        return files

    @staticmethod
    def list_to_tree(data, node_dict):
        """
        将节点列表转换成树形结构字典
        :param data: 带有 id 和 parent_id 属性的节点列表
        :param node_dict: 单节点的数据结构字典
        :return: 树形结构字典
        """

        tree = []

        # 遍历每一个节点,将其添加到父节点的字典或根节点列表中
        for item in data:
            id = item['descendant_id']
            parent_id = item['ancestor_id']

            # 如果父节点为 None,则将当前节点添加到根节点列表中
            if not parent_id:
                tree.append(node_dict[id])
            # 如果父节点存在,则将当前节点添加到父节点的 children 属性中
            else:
                parent = node_dict[parent_id]
                if 'children' not in parent:
                    parent['children'] = []
                parent['children'].append(node_dict[id])

        return tree

    @classmethod
    def delete_file(cls, file_id):
        """
         文件删除
        """
        res1 = cls.DETAIL_CLIENT.objects.filter(id=file_id).update(is_del=True)
        logger.info('%s delete_file. file_id:%s, count:%s', cls.NAME, file_id, res1)
        res2 = cls.RELATION_NODE_CLIENT.remove_node(file_id)

        return res1, res2

    @classmethod
    def search_file(cls, file_name):
        """
        搜索文件
        """
        query_set = cls.DETAIL_CLIENT.objects.filter(file_name__icontains=file_name) \
            .values('id', 'file_name', 'path', 'is_file')
        file_list = []
        for file in query_set:
            file_dict = dict(
                id=file['id'],
                name=file['file_name'],
                is_file=file['is_file'],
                filePath='media/dm_upload' + file['path']
            )
            file_list.append(file_dict)
        return file_list

    @classmethod
    def get_file_url(cls, file_id, file_obj=None):
        """
        获取文件下载链接
        """
        file_url = ''
        if not file_obj:
            file_obj = cls.DETAIL_CLIENT.objects.filter(id=file_id).first()
        if file_obj:
            file_url = 'http://127.0.0.1:8000/' + cls.FILE_SAVE_DIR + file_obj.path + file_obj.file_name
        return file_url

除此之外,还有移动、复制文件(夹)。移动就是先删除再新增文章来源地址https://www.toymoban.com/news/detail-729781.html

到了这里,关于django 实现:闭包表—树状结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于Qt数据库项目实现(Sqlite3为例)|考查数据库、表格(QTableView 显示)(进阶)

    01 数据库表格(QTableView 显示) 本小节设计一个生活中的例子,使用数据库修改/查询员工的编号、姓名、年龄、性别与照片信息。 本例将数据库的内容显示到 QTableView 上。如果只是简单的显示数据库的内容到QTableView 上,可以使用下面的方法,此方法 QTableView 上可以看到

    2024年02月20日
    浏览(46)
  • django使用ztree实现树状结构效果,子节点实现动态加载(l懒加载)

         由于最近项目中需要实现树状结构的效果,考虑到ztree这个组件大家用的比较多,因此打算在django项目中集成ztree来实现树状的效果。最终实现的示例效果如下:         点击父节点,如果有子节点,则从后台动态请求数据,然后显示出子节点的数据。             

    2024年02月14日
    浏览(51)
  • Android使用SQLite数据库实现基本的增删改查

    目录 一、创建activity_main和MainActivity界面 二、实现查询/删除功能创建activity_delete和DeleteActivity 三、实现添加功能创建activity_add和AddActivity  四、实现更新功能创建activity_update和UpdateActivity 五、创建user_data类、userInfo类和增加权限 总结 activity_main如图:  MainActivity如下 layout界面

    2024年02月08日
    浏览(48)
  • 基于Qt数据库项目实现(Sqlite3为例)|考查数据库、绘制(画家)、事件等知识点(进阶)

    坚持最初的梦想,扬帆起航,乘风破浪,永不言败。 01 数据库 数据库是什么?简易言之,就是保存数据的文件。可以存储大量数据,包括插入数据、更新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计

    2024年02月19日
    浏览(45)
  • pycharm社区版使用SQLite连接数据库,并实现数据的增删改查

    社区版找不到数据库,需要先安装Database Navigator插件,之后才能通过sqlite3连接数据库。 ①文件 — ②设置 — ③插件 — ④Marketplace搜索database — ⑤安装Database Navigator — ⑥应用确定 安装之后就可以在页面左侧边栏找到DB Browser,也可以拖动移动到页面右侧。找不到的可以在视

    2024年01月17日
    浏览(50)
  • 基于Linux系统聊天室增加数据库sqlite功能实现(08)

    全部掌握后,开始进入本篇。 为了方便编译,现在我们将前面文章的代码结构做如下调整。 最终增加了数据的文件目录如下: clean.sh  用于清除临时文件 gcc.sh  用于编译整个工程 服务端代码放置到chat_server目录下;客户端代码放置到chat_client目录下; 数据库相关代码放在

    2024年02月07日
    浏览(44)
  • 根据源码,模拟实现 RabbitMQ - 通过 SQLite + MyBatis 设计数据库(2)

    目录 一、数据库设计 1.1、数据库选择 1.2、环境配置 1.3、建库建表接口实现 1.4、封装数据库操作 1.5、针对 DataBaseManager 进行单元测试 1.6、心得 MySQL 是我们最熟悉的数据库,但是这里我们选择使用 SQLite,原因如下: SQLite 比 MySQL 更轻量:一个完整的 SQLite 数据库,只有一个单

    2024年02月13日
    浏览(43)
  • 使用Django数据库模型中的ForeignKey()形成数据表记录的父子层次结构

    可以把ForeignKey()的第1个参数设置为值 “self” 实际形成数据表记录的父子层次结构。 下面是一个简单的实例: 在文件 E:Python_projectP_001myshop-testmyshopapp1models.py 中写入下面的代码: 启动数据库… 然后执行数据库迁移指令: 接下来在文件 E:Python_projectP_001myshop-testmyshop

    2024年02月16日
    浏览(65)
  • 【Android入门到项目实战--4.5】—— SQLite数据库存储实现增删改查

    目录 一、添加数据 二、更新数据 三、删除数据 四、查询数据 使用完整SQL语言操作数据库 1、添加数据  2、更新数据 3、删除数据  4、查询数据 前面学习了创建和升级数据库,本篇文章主要讲解SQLite数据库存储实现增删改查(CRUD)操作。         调用SQLiteOpenHelper的get

    2024年02月04日
    浏览(52)
  • Android——Sqlite数据库——实现联系人信息的添加、查询、修改以及删除功能

        掌握常用布局和基本控件的使用方法     掌握界面图像显示的使用方法     掌握SQLite数据库的创建和基本操作方法 通过线性布局和相对布局来搭建Activity界面,在MainActivity中编写逻辑代码,运行程序,输入两条联系人信息分别点击“添加”“查询”“修改”“

    2024年02月07日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包