如何创建动态嵌套的json,然后可以存储,重新加载和编辑?

时间:2019-04-25 19:42:39

标签: python json dictionary

我想提供以后可以由用户编辑的模板。 因此,它应该是人类可读的.json对象。

仅包含一个字段的模板示例:

{"template_name": "sample_name",
"attribute_fields":
[{"attribute_name": "banana",
  "attribute_tags": ["chiquita", "pinkylady"], 
  "attribute_numbers": [[1, 2, 3, 4] [5, 6, 7, 8]]}]
}

我想动态扩展此json,因为有时会添加更多字段-因此应该有更多的“ attribute_fields”

像这样:

{"template_name": "sample_name",
"attribute_fields":
[{"attribute_name": "banana",
  "attribute_tags": ["chiquita", "pinkylady"], 
  "attribute_numbers": [[1, 2, 3, 4] [5, 6, 7, 8]]},
{attribute_name": "apple",
  "attribute_tags": ["applejack", "applepie"],
  "attribute_numbers": [[123, 45] [666] [5, 5, 5, 5]]}]
}

到目前为止,我已经通过创建一个空的defaultdict来做到这一点,

empty_template = collections.defaultdict(list) 
#yes I used a list.. don't know if there would've been a better option, just tried it and sticked to it
empty_template["template_name"].append(template_name)

looks like this
{"template_name": "sample_name"}

or, printing it, it looks exactly like this:
defaultdict(<class 'list'>, {'template_name': ['sample_name']})

然后创建具有所有所需属性的新defaultdict,然后将此新defaultdict(new_attribute_dict)附加到旧defaultdict(template_to_be_extended)。

def add_attribute_to_template:
new_attribute_dict = create_new_attribute_dict(attribute_name, attribute_tags, attribute_numbers)
 template_to_be_extended["attribute_fields"].append(new_attribute_dict)


#create_new_attribute_dict looks like this:
    # create empty dictionary
    attribute_dict = collections.defaultdict(list)

    # add all attribute properties
    attribute_dict["attribute_name"] = attribute_name
    ... and so on

之后,我将这个扩展模板json.dump并将其放入数据库中。到这里为止,一切似乎都还可以(但我真的认为应该有一种更漂亮的方法来实现这一目标?)。

在我用json.loads读回它之后,我必须再次从该json字符串中做出一个defaultdict,以便可以附加键值对(attribute_fields)。这是所有事情变得很糟糕的地方,我不知道该怎么办。我这样尝试:

template_to_be_extended = collections.defaultdict(lambda: json.loads(template_persistence.get(template_name))) #template_persistence returns the file from my database

extended_template = template_creator.add_attribute_to_template(template_to_be_extended,
                                                        attribute_name, attribute_tags, attribute_numbers)

但是我真的不知道。会以为我可以再次获得defaultdict,而无需使用lambda,但这会引发错误(TypeError:第一个参数必须可调用或无)-因此我将其设为可调用.. ugh ..

这样,我得到了AttributeError:'dict'对象没有属性'append',所以我也尝试从extended_template中创建一个defaultdict

extended_template = collections.defaultdict(lambda: template_creator.add_attribute_to_template(template_to_be_extended,
                                                        attribute_name, attribute_tags, attribute_numbers))

错误消失了,但是打印扩展模板只会返回一个空的{}。

这个问题坚持了几个小时,现在看不到任何东西。也许盯着它太久了。 会对所有提示或其他实现结果的方式感到满意(重要的是我以后可以使用反序列化的json对象中的列表)。

预先感谢

卡尔萨里

1 个答案:

答案 0 :(得分:1)

我将自由调整您存储模板的方式,并提出以下(示例)结构:

{
    "template1": [
        {
            "attribute_name": "banana",
            "attribute_tags": ["chiquita", "pinkylady"],
            "attribute_numbers": [[1, 2, 3, 4], [5, 6, 7, 8]]
        },
        {
            "attribute_name": "apple",
            "attribute_tags": ["applejack", "applepie"],
            "attribute_numbers": [[123, 45], [666], [5, 5, 5, 5]]
        }
    ],
    "template2": [
        {
            "attribute_name": "fwafaw",
            "attribute_tags": ["fawg", "gawggwa"],
            "attribute_numbers": [[22]]
        },
        {
            "attribute_name": "vccbx",
            "attribute_tags": ["vzvvxz", "wgagaw"],
            "attribute_numbers": [[123, 66], [5, 5]]
        }
    ]
}

基本上,您将模板保存在字典中,每个键代表模板名称,其中值是属性列表。

您可以使用pickle将整个内容作为二进制文件存储在文件中,您可以像以前一样从文件中检索它,从而避免了JSON序列化/反序列化。

示例代码:

import pickle
from collections import defaultdict

# initialize the templates variable
templates = defaultdict(list)

# add the first template
templates['template1'].append({
    "attribute_name": "banana",
    "attribute_tags": ["chiquita", "pinkylady"],
    "attribute_numbers": [[1, 2, 3, 4], [5, 6, 7, 8]]
})

# store the templates data to a binary file
with open("templates.data", "wb") as pf:
    pickle.dump(templates, pf)

# retrieve the templates from the binary file
with open("templates.data", "rb") as pf:
    retrieved_templates = pickle.load(pf)

# let's inspect the retrieved templates, it will be exactly like the initial structure
print(retrieved_templates)

# let's append a new attribute to the template
retrieved_templates['template1'].append({
    "attribute_name": "apple",
    "attribute_tags": ["applejack", "applepie"],
    "attribute_numbers": [[123, 45], [666], [5, 5, 5, 5]]
})

# restore the templates data
with open("templates.data", "wb") as pf:
    pickle.dump(retrieved_templates, pf)

# re-retrieve the templates
with open("templates.data", "rb") as pf:
    retrieved_templates_second = pickle.load(pf)

# will display with the updated attributes
print(retrieved_templates_second)

如果要在控制台中运行它,则将具有:

defaultdict(<class 'list'>, {'template1': [{'attribute_name': 'banana', 'attribute_tags': ['chiquita', 'pinkylady'], 'attribute_numbers': [[1, 2, 3, 4], [5, 6, 7, 8]]}]})

然后是

defaultdict(<class 'list'>, {'template1': [{'attribute_name': 'banana', 'attribute_tags': ['chiquita', 'pinkylady'], 'attribute_numbers': [[1, 2, 3, 4], [5, 6, 7, 8]]}, {'attribute_name': 'apple', 'attribute_tags': ['applejack', 'applepie'], 'attribute_numbers': [[123, 45], [666], [5, 5, 5, 5]]}]})

此代码旨在概述您要实现的目标,因此,如果要隐藏这些操作并在函数和类下进行概括,请尝试保持此脚本中提供的流程。