[英]Work with a columnar Pandas dataframe data format to generate a hierarchical tree structure
[英]Generate hierarchical JSON tree structure from Django model
我有一個Django模型
class Classification(models.Model):
kingdom = models.CharField(db_column='Kingdom', max_length=50)
phylum = models.CharField(db_column='Phylum', max_length=50)
class_field = models.CharField(db_column='Class', max_length=50)
order = models.CharField(db_column='Order', max_length=50)
family = models.CharField(db_column='Family', max_length=50)
genus = models.CharField(db_column='Genus', max_length=50)
species = models.CharField(db_column='Species', max_length=50)
表示生物分類學分類,如下所示:
我有超過5000種的分類記錄。 我需要生成JSON層次結構,如下所示。
{
'name': "root",
'children': [
{
'name': "Animalia",
'children': [
{
{
'name':"Chordata"
'children': [ ... ]
}
},
...
...
]
},
...
...
]
}
你能建議我這樣做的方法嗎?
您可以執行以下操作:
Classifications
列表轉換為嵌套的dict。 此處的示例將在略微降低的Classification
級別上運行,以提高可讀性:
class Classification:
def __init__(self, kingdom, phylum, klass, species):
self.kingdom = kingdom
self.phylum = phylum
self.klass = klass
self.species = species
第一部分:
from collections import defaultdict
# in order to work with your actual implementation add more levels of nesting
# as lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
nested_dict = defaultdict(
lambda: defaultdict(
lambda: defaultdict(list)
)
)
for c in all_classifications:
nested_dict[c.kingdom][c.phylum][c.klass].append(c.species)
defaultdict
只是一個很好的工具,可以保證字典中密鑰的存在,它接收任何可調用的函數並使用它來創建缺失密鑰的值。
現在我們有了很好的嵌套字典
{
'Kingdom1': {
'Phylum1': {
'Class1': ["Species1", "Species2"],
'Class2': ["Species3", "Species4"],
},
'Phylum2': { ... }
},
'Kingdom2': { 'Phylum3': { ... }, 'Phylum4': {... } }
}
第二部分:轉換為所需的輸出
def nested_to_tree(key, source):
result = {'name': key, 'children':[]}
for key, value in source.items():
if isinstance(value, list):
result['children'] = value
else:
child = nested_to_tree(key, value)
result['children'].append(child)
return result
tree = nested_to_tree('root', nested_dict')
我相信這是不言自明的 - 我們只是將傳遞的字典轉換為所需的格式並遞歸到它的內容以形成孩子。
完整的例子在這里 。
兩個筆記:
source.items()
替換source.iteritems()
應該足以在python 2中運行。 genus
所有species
作為children
附着的genus
。 如果你想讓species
成為葉子節點 - 修改代碼是非常簡單的。 如果您在執行此操作時遇到任何問題,請在評論中告訴我。 終於得到了我想要的東西。 代碼不漂亮,近乎難看,但不知怎的,我得到了我想要的東西。
def classification_flare_json(request):
#Extracting from database and sorting the taxonomy from left to right
clazz = Classification.objects.all().order_by('kingdom','phylum','class_field','genus','species')
tree = {'name': "root", 'children': []}
#To receive previous value of given taxa type
def get_previous(type):
types = ['kingdom', 'phylum', 'class_field', 'family', 'genus', 'species']
n = types.index(type)
sub_tree = tree['children']
if not sub_tree: return None
for i in range(n):
if not sub_tree: return None
sub_tree = sub_tree[len(sub_tree)-1]['children']
if not sub_tree: return None
last_item = sub_tree[len(sub_tree)-1]
return last_item['name']
#To add new nodes in the tree
def append(type, item):
types = ['kingdom', 'phylum', 'class_field', 'family', 'genus', 'species_id']
n = types.index(type)
sub_tree = tree['children']
for i in range(n+1):
if not sub_tree: return None
sub_tree = sub_tree[len(sub_tree)-1]['children']
sub_tree.append(item)
for item in clazz:
while True:
if item.kingdom == get_previous('kingdom'):
if item.phylum == get_previous('phylum'):
if item.class_field == get_previous('class_field'):
if item.family == get_previous('family'):
if item.genus == get_previous('genus'):
append('genus', {'name':item.species, 'size': 1})
break;
else:
append('family', {'name':item.genus, 'children': []})
else:
append('class_field', {'name':item.family, 'children':[]})
else:
append('phylum', {'name': item.class_field, 'children':[]})
else:
append('kingdom', {'name': item.phylum, 'children':[]})
else:
tree['children'].append({'name': item.kingdom, 'children':[]})
return HttpResponse(json.dumps(tree), content_type="application/json")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.