Sub-directory 为 Flask 网络应用制作 in-memory 文件系统时出现问题

Sub-directory problem when making in-memory file system for Flask web app

我正在创建一个 virtual/in-memory 文件系统作为 Flask 应用程序的一部分,用户在其中创建文件和文件夹,我将它们保存在 SQL 数据库中并显示目录树回到 UI 中的用户(想想 dropbox/google 驱动器)。

为了 reprex,'File' 和 'Folder' SQL 表中的相关元数据为:['object_id', 'parent_id', 'child_nodes'] 其中,

我创建了项目和文件 类 来处理内部方法和属性(排除但必需)。所以理想情况下,我的最终解决方案中需要 类。

我 运行 遇到的主要问题是将 sub-directories 作为 child_nodes 附加到目录。 这是可以观察到的 [在评论中从 dir_list[1] 迭代到 dir_list[2] 时,dir_list[1] 已经附加到 dir_list[0],因此不会反映以下迭代。

正在寻找有关如何实现它的任何建议。我也完全愿意完全使用不同的数据结构,只要我可以添加元数据并按照与 FileDir.create_tree() 相同的方式对其进行格式化。 注意:我需要遍历理论上无限的数字子目录,而不仅仅是我的 reprex 中的内容。

# Objects for organizing each struct -----
class File():
    def __init__(self, file_list):
        self.id = file_list[0]
        self.name = file_list[1]
        self.parent = file_list[2]
        self.directory = False

class Directory:
    def __init__(self, dir_list):
        self.id = dir_list [0]
        self.name = dir_list [1]
        self.parent = dir_list [2]
        self.child_nodes = []
        self.directory = True

    def add_file_node(self, node):

        node = {
                'id': node.id,
                'name':  node.name,
                'parent': self.parent,
                'is_dir': node.directory
            }
        self.child_nodes.append(node)

    def add_dir_node(self, node):

        node = {
                'id': node.id,
                'name':  node.name,
                'parent': self.parent,
                'is_dir': node.directory,
                'children': self.child_nodes
            }
        self.child_nodes.append(node)


    def return_tree(self):
        tree = {
            'name': self.name,
            'children': self.child_nodes,
            'parent': self.parent,
            'is_directory': self.directory
        }
        return tree



class FileDir():
    def __init__(self, dir_list):
        self.dir_list = dir_list
    def create_tree(self):
        tree = []
        for directory in self.dir_list:
            tree.append(directory.return_tree())
        return tree

# Example Data (formatted as 2d-list from my SQL query) -----
dir_list = [
         ['10001', 'dir_1', None],
         ['10002', 'dir_2', '10001'],
         ['10003', 'dir_3', '10002'],
         ['10004', 'dir_4', None]
     ]

file_list = [
         ['21110', 'file1.csv', None],
         ['21111', 'file2.csv', '10001'],
         ['21112', 'file3.csv', '10002'],
         ['21113', 'file3.csv', '10003']
     ]

dir_objs = [Directory(d) for d in dir_list]
file_objs = [File(f) for f in file_list]

for fil in file_objs:
    if fil.parent:
        for i, x in enumerate(dir_objs):
            if fil.parent == x.id:
                x.add_file_node(fil)


# TODO Append sub_folders
# ...
# 
# for d in dir_objs:
#    if d.parent:
#        for i, x in enumerate(dir_objs):
#            if d.parent == x.id:
#                x.add_dir_node(d)
#                dir_objs.remove(d)

tree = FileDir(dir_objs)
tree.create_tree()

这段代码能满足您的需求吗?


# Objects for organizing each struct -----
class File:
    def __init__(self, file_list):
        self.id = file_list[0]
        self.name = file_list[1]
        self.parent = file_list[2]
        self.directory = False

class Directory:
    def __init__(self, dir_list):
        self.id = dir_list[0]
        self.name = dir_list[1]
        self.parent = dir_list[2]
        self.child_nodes = []
        self.directory = True

    def add_file_node(self, node):

        node = {
                'id': node.id,
                'name':  node.name,
                'parent': self.parent,
                'is_dir': node.directory
            }
        self.child_nodes.append(node)

    def add_dir_node(self, node):

        node = {
                'id': node.id,
                'name':  node.name,
                'parent': self.parent,
                'is_dir': node.directory,
                'children': self.child_nodes
            }
        self.child_nodes.append(node)


    def return_tree(self):
        tree = {
            'name': self.name,
            'children': self.child_nodes,
            'parent': self.parent,
            'is_directory': self.directory
        }
        return tree



class FileDir:
    def __init__(self, dir_list):
        self.dir_list = dir_list
    def create_tree(self):
        tree = []
        for directory in self.dir_list:
            tree.append(directory.return_tree())
        return tree

# Example Data (formatted as 2d-list from my SQL query) -----
dir_list = [
         ['10001', 'dir_1', None],
         ['10002', 'dir_2', '10001'],
         ['10003', 'dir_3', '10002'],
         ['10004', 'dir_4', None]
     ]

file_list = [
         ['21110', 'file1.csv', None],
         ['21111', 'file2.csv', '10001'],
         ['21112', 'file3.csv', '10002'],
         ['21113', 'file3.csv', '10003']
     ]

dir_objs = [Directory(d) for d in dir_list]
file_objs = [File(f) for f in file_list]

for fil in file_objs:
    if fil.parent:
        for i, x in enumerate(dir_objs):
            if fil.parent == x.id:
                x.add_file_node(fil)


for dir_obj in dir_objs:
   if dir_obj.parent:
       for potential_parent_dir_obj in dir_objs:
           if dir_obj.parent == potential_parent_dir_obj.id:
               potential_parent_dir_obj.add_dir_node(dir_obj)
dir_objs = [dir_obj for dir_obj in dir_objs if not dir_obj.parent]



tree = FileDir(dir_objs)
tree.create_tree()

这不会处理深度超过两层的目录树,但您的示例数据并未表明这是必要的。如果您确实需要处理深层嵌套的层次结构,请告诉我。您将需要一种不同的方法。


编辑

这是我使用 Python 3.8 开发的更强大的版本,可以处理任意深度。我还没有对其进行广泛的测试,但希望这会有所帮助。没有令人困惑的递归(表面上)。

from __future__ import annotations
from typing import Union, List
from dataclasses import dataclass, asdict, field
import json


@dataclass
class Node:
    node_id: str
    name: str
    parent_node_id: str = None

    def to_tree(self):
        return asdict(self)


@dataclass
class File(Node):
    is_directory: bool = False


@dataclass
class Directory(Node):
    is_directory: bool = True
    children: List[Union[Directory, File]] = field(default_factory=list)

    def add_child(self, child: Union[Directory, File]):
        self.children.append(child)


class FileSystem:

    def __init__(self, *nodes):
        self.nodes = {node.node_id: node for node in nodes}
        for node in self.non_root_nodes:
            self.nodes[node.parent_node_id].add_child(node)

    def __getitem__(self, node_id):
        return self.nodes[node_id]

    @property
    def root_nodes(self):
        return [node for node in self.nodes.values() if node.parent_node_id is None]

    @property
    def non_root_nodes(self):
        return [node for node in self.nodes.values() if node.parent_node_id is not None]

    @property
    def directories(self):
        return [node for node in self.nodes.values() if node.is_directory] 

    @property
    def files(self):
        return [node for node in self.nodes.values() if not node.is_directory]

    def to_tree(self):
        return [node.to_tree() for node in self.root_nodes]



dir_list = [
    # id,      name,    parent_node_id
     ['10001', 'dir_1', None], 
     ['10002', 'dir_2', '10001'],
     ['10003', 'dir_3', '10002'],
     ['10004', 'dir_4', None]
 ]

file_list = [
     ['21110', 'file1.csv', None],
     ['21111', 'file2.csv', '10001'],
     ['21112', 'file3.csv', '10002'],
     ['21113', 'file3.csv', '10003']
]

dir_list = [Directory(*directory) for directory in dir_list]
file_list = [File(*file) for file in file_list]

file_system = FileSystem(*dir_list, *file_list)
tree = file_system.to_tree() 

print(json.dumps(tree, indent=2))