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