Skip to content

Instantly share code, notes, and snippets.

@goldhand
Created August 15, 2013 08:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save goldhand/6239230 to your computer and use it in GitHub Desktop.
Save goldhand/6239230 to your computer and use it in GitHub Desktop.
Things I learned dealing with JSON trees in django
# Things I learned dealing with recursive JSON objects
This is a summary of my findings while dealing with a django model, TaskCategory.
## Two ways for manipulating a set of trees
I found two different ways for manipulating objects with an uncertain amount
of ascendants / descendants. The first involves manipulating an object within
a tree and the second involves taking apart the tree, manipulating the branches
and building a new tree
### General helper functions
def unique_items(list):
unique_list = []
for item in list:
if not item in unique_list:
unique_list.append(item)
return unique_list
def get_dict_in_list(key, value, dict_list):
"""
Looks through a list of dictionaries and returns dict, where dict[key] == value
"""
result = None
for dict in dict_list:
if dict[key] == value:
result = dict
return result
def get_branch_by_id(tree, id):
"""
looks through a tree recursively for dict['id'] == id and returns the branch.
Assumes that each branch item has a key, ['children'], that contains a list of dict objects in the same format as tree
and another key, ['ascendants'], that is a string of ids starting with the dict object's top-level ancestor's id and
each other ancestor ending with that dict object's id i.e
tree =
[
{'id': 1,
'ascendants': "1",
'children': [
{'id': 2,
'ascendants': "1,2",
'children': [
{'id': 4,
'ascendants': "1,2,4",
'children': [
{'id': 5,
'ascendants': "1,2,4,5",
'children': [ ]
}
}
{'id': 3,
'ascendants': "1,2,3",
'children': [ ]
}
}
},
{'id': 6,
'ascendants: "6",
'children: []
}
]
"""
for branch in tree:
if branch['id'] == id:
print branch['id']
return branch
elif branch['children']:
branch = get_branch_by_id(branch['children'], id)
if branch:
return branch
### Modifying the original tree
This function searches through a tree and finds a branch by 'id' then manipulates
the branch with data from 'item'
def add_info_to_branch(tree, id, item):
"""
adds item (branch) to a branch's children and increases price, expense, total of branch to include items values
"""
target = None
for branch in tree:
if branch['id'] == id:
target = branch
elif branch['children']:
target = get_branch_by_id(branch['children'], id)
if target:
target['children'].append(item)
target['price'] += item['price']
target['expense'] += item['expense']
target['total'] += item['total']
### Creating a new tree
The goal here was to take apart the tree set and filter out any unused branches
then rebuild the tree
This process is:
1. Identify branches that are needed
2. Create a list of these branches
3. Modify each branch in the list
4. Rebuild the new tree
def get_used_branch_ids(p_tree):
"""
p_tree = p['category_totals']
returns list of branch ids and all of their ancestor ids, filters redundancies
*NOTE: this is depending on the 'ascendants' method of task categories. If the 'ascendants' method isnt updating
correctly, it is likely the cause of any issues with project summaries
"""
used_object_ids = []
for branch in p_tree:
branch_ascendants = p_tree[branch]['ascendants'].split(',')
branch_ascendants = [int(item) for item in branch_ascendants]
used_object_ids.extend(branch_ascendants)
used_object_ids = unique_items(used_object_ids)
return used_object_ids
def create_used_item_list(tree, used_branch_ids):
"""
using a list of ids, creates a list of branches with those ids
NOTE: any modifications to branches should be done here or immediately after
"""
branches = []
for id in used_branch_ids:
print id
branch = get_branch_by_id(tree, id)
branches.append(branch)
for branch in branches:
branch['children'] = []
return branches
def modify_used_item_list(p_tree, used_item_list):
"""
modify list of branches to include additional key, values
"""
for item in used_item_list:
task_set = []
for task in p_tree[str(item['id'])]['task_set']:
task_set.append(p_tree[str(item['id'])]['task_set'][str(task)])
item['task_set'] = task_set
item['expense'] = p_tree[str(item['id'])]['expense']
item['price'] = p_tree[str(item['id'])]['price']
item['total'] = p_tree[str(item['id'])]['total']
def create_used_item_tree(used_item_list):
"""
takes branches and organizes them into a recursive tree (or whatever this id called??)
branches are modified with "add_info_to_branch" function
"""
used_item_tree = []
for item in used_item_list[:]:
print str(item['id']) + ' : ' + str(item['parent'])
if item['parent'] is None:
print 'primary %d' % item['id']
used_item_tree.append(item)
used_item_list.remove(item)
while len(used_item_list) is not 0:
for item in used_item_list[:]:
parent = get_dict_in_list('id', item['parent'], used_item_list)
if not parent:
add_info_to_branch(used_item_tree, item['parent'], item)
used_item_list.remove(item)
print 'child %d' % item['id']
return used_item_tree
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment