簡體   English   中英

從Django模型生成分層JSON樹結構

[英]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': [ ... ]
                            }
                        },
                        ...
                        ...
                    ]
                },
                ...
                ...
            ]
}

你能建議我這樣做的方法嗎?

您可以執行以下操作:

  1. Classifications列表轉換為嵌套的dict。
  2. 將嵌套的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')

我相信這是不言自明的 - 我們只是將傳遞的字典轉換為所需的格式並遞歸到它的內容以形成孩子。

完整的例子在這里

兩個筆記:

  1. 用python編寫3.用source.items()替換source.iteritems()應該足以在python 2中運行。
  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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM