1

This is strictly academical question, after some messing around - but basically want to know how to make a reddit-style nested comment system if I start with a parent/child relationship (django model)

Given knowledge of each record's parent, and some data associated with the record, how do I create a tree structure of arbitrary depth where each node (record) in my tree will not only contain info about it's relationship to other records (by virtue of position in tree), but also have data associated with it

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

First issue was getting the parent-child rels (not yet worrying about associating data with parent).

This person Django how to make ul li hierachy from a self reference model accomplished turning similar data structure to nested unordered html list and I tried it too, works great.

But I want a data structure I can work with, like a dictionary or something.

Originally, when I started working on this problem, I wasn't thinking in terms of reddit-style comments, I actually was working on moving a hierarchical db (these were popular a LONG time ago) to my django app, my django 'Records' table is a representation of the hierarchical relationship:

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

I wanted something like

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

And was able to do that with collections defaultdict (lots of HN posts inspiration for solution, such as How do I build a tree dynamically in Python)

My solution:

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)

So, say I had sr.data (ie. the comment content if I were building a nested comment system) as my data parameter going into the recursive add_element(root, path, data) function, then on the next recursion I would get a TypeError - 'str' does not support data assignment. So I made the data parameter (new node) a dictionary, so that recursion could continue. This succesfully creates multi-level dict structure as shown above.

But what If I want something like:

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

How would I change my add_element recursive function to accomodate that? I think I have an idea, now that I have written it all out.

amchugh89
  • 1,276
  • 1
  • 14
  • 33

0 Answers0