Динамическое дерево из родительско-дочерних отношений в python, с данными, связанными с узлами - PullRequest
0 голосов
/ 08 декабря 2018

Это чисто академический вопрос, после некоторого возни - но в основном я хочу знать, как создать систему вложенных комментариев в стиле Reddit, если я начну с отношения родитель / ребенок (модель django)

Учитывая знание родителя каждой записи и некоторые данные, связанные с этой записью, как мне создать древовидную структуру произвольной глубины, где каждый узел (запись) в моем дереве будет не только содержать информацию о своих отношениях с другими записями (в силув древовидной структуре), но также имеют связанные с ним данные

class Record(models.Model):
    name = models.CharField(max_length=100, null=True, blank=True)
    parent = models.ForeignKey('Record', verbose_name='Hierarchical Parent', on_delete=models.CASCADE, null=True, blank=True)
    data = models.TextField()
    generation = models.IntegerField()

Первая проблема заключалась в получении зависимостей родитель-потомок (пока не беспокоился о связи данных с родителем).

Этот человек Django, как сделать ul li hierachy из собственной эталонной модели , превратил структуру данных, похожую на вложенный неупорядоченный список HTML, и я тоже попробовал, отлично работает.

Но я хочу данныеструктура, с которой я могу работать, как словарь или что-то.

Первоначально, когда я начал работатьЗная об этой проблеме, я не думал с точки зрения комментариев в стиле Reddit, я фактически работал над перемещением иерархической базы данных (это было очень давно) в мое приложение django, мое django 'Таблица записей - это представление иерархических отношений:

Name   |  Parent
----------------
Account | None
Loan  | Account
Escrow | Loan
Person | Account
AccHx | Account
LoanHx | Loan

Я хотел что-то вроде

{'Account':
    {'Loan':
        {'LoanHx':{},
         'Escrow':{}
        },
     'Person':{},
     'AccHx':{}
     }
}

И смог сделать это с коллекциями defaultdict (много сообщений HN вдохновляет на решение, например Как динамически построить дерево в Python )

Мое решение:

def add_element(root, path, data):
    if len(path) == 1:
        root[path[0]] = data
    else:
        add_element(root[path[0]], path[1:], data)

import collections
tree = lambda: collections.defaultdict(tree)
root = tree()
# add_element(root, ['toplevel', 'secondlevel', 'thirdlevel'], 1)
# add_element(root, ['toplevel', 'anotherlevel'], 2)

selected_records = Record.objects.all()[0:5]

#I have a generation field
for sr in selected_records:
    if sr.generation == 0:
        add_element(root, [sr.name], {})#sr.data)
    elif sr.generation == 1:
        add_element(root, [sr.parent.name, sr.name], {})#sr.data)
    elif sr.generation == 2:
        add_element(root, [sr.parent.parent.name, sr.parent.name, sr.name], {})#sr.data)
    elif sr.generation == 3:
        add_element(root, [sr.parent.parent.parent.name,
                           sr.parent.parent.name, sr.parent.name, sr.name], {})#sr.data)

Итак, скажем, у меня были sr.data (т.е.содержимое комментария, если бы я строил вложенную систему комментариев) в качестве параметра данных, входящего в рекурсивную функцию add_element (root, path, data), то при следующей рекурсии я получал бы TypeError - 'str' не поддерживает назначение данных.Поэтому я сделал параметр данных (новый узел) словарем, чтобы рекурсия могла продолжаться.Это успешно создает многоуровневую структуру dict, как показано выше.

Но что, если я хочу что-то вроде:

{'Account':
    {'fields':['id','name',....],
     'children':
               {'Loan':
                    {'fields':['id','name',....],
                     'children':
                            {'LoanHx':{'fields':['id','name',....],
                     'children':{}},
 ....

Как бы я изменил свою рекурсивную функцию add_element, чтобы приспособиться к этому?Я думаю, у меня есть идея, теперь, когда я все это написал.

...