当前位置: 首页 > news >正文

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

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

闭包表模型

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

场景

我们 基于 django orm实现一个文件树,文件夹直接可以实现无限嵌套
在这里插入图片描述

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'数字人文件关系表'
idfile_name
1AAA
2aaa.pdf
idancestor_iddescendant_iddepth
1110
2220
3121

增删改查

class DmRelationNode:"""关系节点"""NAME = "DmRelationNode"RELATION_CLIENT = DmFileRelation@classmethoddef 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@classmethoddef 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_mapfor 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@classmethoddef 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@classmethoddef 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@classmethoddef 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@classmethoddef 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 = DmFileDetailRELATION_NODE_CLIENT = DmRelationNodeFILE_SAVE_DIR = 'media/dm/'@classmethoddef 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_dictreturn file_map@classmethoddef 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 Falseres = cls.RELATION_NODE_CLIENT.insert_relation_node(node_id=file_obj.id, user_id=user_id, parent_id=parent_id)if not res:return Falsereturn dict(id=file_obj.id, name=file_name)@classmethoddef 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)# 过滤0ancestor = list(filter(lambda x: x > 0, ancestor))# 排序ancestor.sort()path = '/'.join(map(str, ancestor))return '/' + path + '/' if path else '/'@classmethoddef 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@classmethoddef 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@staticmethoddef 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@classmethoddef 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@classmethoddef 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@classmethoddef 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_namereturn file_url

除此之外,还有移动、复制文件(夹)。移动就是先删除再新增

相关文章:

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

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

Redis与分布式-集群搭建

接上文 Redis与分布式-哨兵模式 1. 集群搭建 搭建简单的redis集群,创建6个配置,开启集群模式,将之前配置过的redis删除,重新复制6份 针对主节点redis 1,redis 2,redis 3都是以上修改内容,只是…...

C++--位图和布隆过滤器

1.什么是位图 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。比如int 有32位,就可以存放0到31这32个数字在不在某个文件中。当然,其他类型也可以。 2.位…...

linux常识

目录 i.mx6ull开发板配置ip 静态IP配置 命令行配置 配置文件配置 动态IP配置 命令行配置 配置文件配置 为什么编译驱动程序之前要先编译内核? init系统服务 systemv守护进程 systemd守护进程 i.mx6ull开发板配置ip i.mx6ull有两个网卡(eth0和…...

Codeforces Round 901 (Div. 1) B. Jellyfish and Math(思维题/bfs)

题目 t(t<1e5)组样例&#xff0c;每次给出a,b,c,d,m(0<a,b,c,d,m<2的30次方) 初始时&#xff0c;(x,y)(a,b)&#xff0c;每次操作&#xff0c;你可以执行以下四种操作之一 ①xx&y&#xff0c;&为与 ②xx|y&#xff0c;|为或 ③yx^y&#xff0c;^为异或 …...

unity 鼠标标记 左键长按生成标记右键长按清除标记,对象转化为子物体

linerender的标记参考 unity linerenderer在Game窗口中任意画线_游戏内编辑linerender-CSDN博客 让生成的标记转化为ARMarks游戏对象的子物体 LineMark.cs using System.Collections; using System.Collections.Generic; using UnityEngine;public class LineMark : MonoBeh…...

解决mac pro 连接4k显示器严重发烫、卡顿问题

介绍个不用花钱的方法。其实mac自带的风扇散热能力还可以的&#xff0c;但是默认比较懒散&#xff0c;可以用一个软件来控制下&#xff0c;激发下它的潜能。 可以下个stats软件 打开传感器开关&#xff0c;以及同步控制风扇开关 以及cpu显示温度 点击控制台上的温度图标&…...

QT的ui设计中改变样式表的用法

在QT的ui设计中,我们右键会弹出一个改变样式表的选项,很多人不知道这个是干什么的。 首先我们来看下具体的界面 首先我们说一下这个功能具体是干嘛的, 我们在设置很多控件在界面上之后,常常都是使用系统默认的样式,但是当有些时候为了美化界面我们需要对一些控件进行美化…...

零基础Linux_10(进程)进程终止(main函数的返回值)+进程等待

目录 1. 进程终止 1.1 main函数的返回值 1.2 进程退出码和错误码 1.3 进程终止的常见方法 2. 进程等待 2.1 进程等待的原因 2.2 wait 函数 2.3 waitpid 函数 2.4 int* status参数 2.5 int options非阻塞等待 本篇完。 1. 进程终止 进程终止指的就是程序执行结束了&…...

【已解决】opencv 交叉编译 ffmpeg选项始终为NO

一、opencv 交叉编译没有 ffmpeg &#xff0c;会导致视频打不开 在交叉编译时候&#xff0c;发现在 pc 端能用 opencv 打开的视频&#xff0c;但是在 rv1126 上打不开。在网上查了很久&#xff0c;原因可能是 交叉编译过程 ffmpeg 造成的。之前 ffmpeg 是直接用 apt 安装的&am…...

rust生命期

一、生命期是什么 生命期&#xff0c;又叫生存期&#xff0c;就是变量的有效期。 实例1 {let r;{let x 5;r &x;}println!("r: {}", r); }编译错误&#xff0c;原因是r所引用的值已经被释放。 上图中的绿色范围’a表示r的生命期&#xff0c;蓝色范围’b表示…...

实现将一张图片中的目标图片抠出来

要在python中实现将一张图片中的目标图片裁剪出来&#xff0c;需要用到图像处理及机器学习库&#xff0c;以下是一个常用的基本框架 加载图片并使用OpenCV库将其转换为灰度图像 import cv2img cv2.imread(screenshot.jpg) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)准备模…...

Rust 使用Cargo

Rust 使用技巧 Rust 使用crates 假设你正在编写一个 Rust 程序&#xff0c;要使用一个名为 rand 的第三方库来生成随机数。首先&#xff0c;你需要在 Cargo.toml 文件中添加以下依赖项&#xff1a; toml [dependencies] rand "0.7.3" 然后运行 cargo build&…...

【k8s】集群搭建篇

文章目录 搭建kubernetes集群kubeadm初始化操作安装软件(master、所有node节点)Kubernetes Master初始化Kubernetes Node加入集群部署 CNI 网络插件测试 kubernetes 集群停止服务并删除原来的配置 二进制搭建(单master集群)初始化操作部署etcd集群安装Docker部署master节点解压…...

10.1select并发服务器以及客户端

服务器&#xff1a; #include<myhead.h>//do-while只是为了不让花括号单独存在&#xff0c;并不循环 #define ERR_MSG(msg) do{\fprintf(stderr,"%d:",__LINE__);\perror(msg);\ }while(0);#define PORT 8888//端口号1024-49151 #define IP "192.168.2.5…...

几个好用的测试HTTP请求的网站

Reqres (https://reqres.in)&#xff1a;Reqres提供了一个模拟的REST API&#xff0c;您可以使用它来测试POST、GET、PUT等HTTP请求&#xff0c;并获得相应的响应结果。 JSONPlaceholder (https://jsonplaceholder.typicode.com)&#xff1a;JSONPlaceholder是一个免费的JSON测…...

kafka简易搭建(windows环境)

1&#xff0c;下载 Apache Kafka 查找 kafka_2.13-3.2.1.tgz 2&#xff0c;java版本需要17以上 3&#xff0c;配置server.properties的log.dirs目录、zookeeper.properties 的dataDir目录 windows反斜杠地址 4&#xff0c;启动 cd D:\app\kafka_2.13-3.2.1 .\bin\window…...

毕业设计选题uniapp+springboot新闻资讯小程序源码 开题 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…...

Linux系统编程基础:进程控制

文章目录 一.子进程的创建操作系统内核视角下的父子进程存在形式验证子进程对父进程数据的写时拷贝 二.进程等待进程非阻塞等待示例: 三.进程替换内核视角下的进程替换过程:综合利用进程控制系统接口实现简单的shell进程 进程控制主要分为三个方面,分别是:子进程的创建,进程等待…...

选择和操作元素

上一篇文档我们介绍了DOM元素和DOM的获取&#xff1b;其实除了获取DOM&#xff0c;我们也可以去替换DOM元素中的文本 document.querySelector(.message).textContent "&#x1f389;Correct Number"● 除此之外&#xff0c;我们可以设置那个数字部分 document.que…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...