Проблема с подкаталогом при создании файловой системы в памяти для веб-приложения Flask

Я создаю виртуальную/в памяти файловую систему как часть приложений Flask, где пользователь создает файлы и папки, и я сохраняю их в базе данных SQL и отображаю дерево каталогов обратно пользователю в пользовательском интерфейсе ( подумайте о дропбоксе/гугл диске).

Для репрекса соответствующие метаданные в SQL-таблицах «Файл» и «Папка» будут следующими: ['object_id', 'parent_id', 'child_nodes'] где,

  • object_id = уникальный идентификатор
  • parent_id = родительский object_id, которому принадлежит подфайл или подпапка
  • child_nodes = дочерние object_ids родителя

Я создал классы Project и File для обработки внутренних методов и свойств (исключенных, но необходимых). Поэтому в идеале мне нужны классы в моем конечном решении.

Основная проблема, с которой я сталкиваюсь, это добавление подкаталогов как child_nodes к каталогам. Это видно [в закомментированном коде внизу] при итерации от dir_list[1] к dir_list[2], где dir_list[1] уже было бы добавлено к dir_list[0] и, следовательно, не отражало бы следующую итерацию.

Ищу любое предложение о том, как это реализовать. Я также полностью открыт для использования различных структур данных, если я могу добавлять метаданные и форматировать их так же, как это делает FileDir.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)


# 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()
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
149
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Соответствует ли этот код вашим потребностям?


# 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))

Да, мне нужно пройти теоретически бесконечное количество уровней. Спасибо, что указали на это, я обновлю вопрос. Моя интуиция подсказывает мне, что это можно сделать с помощью надежного рекурсивного алгоритма, просто я не уверен, каким будет базовый случай. Но также не уверен, будет ли это вычислительно эффективным

mfnight 16.12.2020 08:48

Без проблем. - Здесь 3:15 утра. Завтра я обновлю свой ответ более надежным решением, которое может обрабатывать произвольно глубокие иерархии.

Kapocsi 16.12.2020 09:19

@mfnight Ознакомьтесь с исправленным кодом, который я разместил выше.

Kapocsi 17.12.2020 06:10

Я также использую v3.8, и у меня не было проблем. Сравнительные тесты также достаточно хороши для больших наборов данных. Спасибо!

mfnight 17.12.2020 10:45

Другие вопросы по теме