I'm trying to create an org chart based on a model that references itself through an attribute called reports_to. I don't know how many levels down the org chart will go, so I feel like a recursive function makes sense. Here's some code that works at the moment:
top_level = Person.objects.filter(reports_to=None)
org_chart = {}
for person in top_level:
org_chart[person] = {}
if person.has_direct_reports():
direct_reports = Person.objects.filter(reports_to=person)
for p in direct_reports:
org_chart[person][p] = {}
if p.has_direct_reports():
direct_reports_2 = Person.objects.filter(reports_to=p)
for q in direct_reports_2:
org_chart[person][p][q] = {}
# ... and so on
This results in a shell output like this:
>>> pp.pprint(org_chart)
{ <Person: Joe Boss>: { <Person: John Doe>: { <Person: John Doe Jr>: { },
<Person: Jane Doe>: { }}},
<Person: Partner Mary>: {}}
Which is correct. Shown cleaner:
Joe Boss
- John Doe
-- John Doe Jr
-- Jane Doe
Partner Mary
I've been trying to convert this code to a recursive function, but my brain just won't get around the problem. Thanks for any advice or help in solving this!
Edit. Here's the code I'm trying to make work, but I'm falling over myself in the process:
def direct_reports_r(person):
if person.has_direct_reports():
direct_reports = Person.objects.filter(reports_to=person)
for person in direct_reports:
org_chart[person] = {}
if person.has_direct_reports():
direct_reports = Person.objects.filter(reports_to=person)
org_chart[person] = direct_reports_r(person)
else:
return person
else:
return False
top_level = Person.objects.filter(reports_to=None)
org_chart = {}
for person in top_level:
org_chart[person] = {}
# recursion
org_chart[person][direct_reports_r(person)] = {}
I hope this code works.
def foo(person, tmp_root):
tmp_root[person] = {}
if person.has_direct_reports():
direct_reports = Person.objects.filter(reports_to=person)
for p in direct_reports:
foo(p, tmp_root[person])
org_chart = {}
top_level = Person.objects.filter(reports_to=None)
for person in top_level:
foo(person, org_chart)
Passed lists are mutable, as well as dictionaries so when you pass it into an argument, it's by reference. Here's an example you can play with to achieve the desired result.
top_level = Person.objects.filter(reports_to=None)
org_chart = {}
def init_org_chart(reports, arg):
for person in reports:
arg[person] = {}
if person.has_direct_reports():
direct_reports = Person.objects.filter(reports_to=person)
init_org_chart(direct_reports, arg[person])
init_org_chart(top_level, org_chart)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With