首页 > 解决方案 > 如何创建一个动态的嵌套 json,可以在之后存储和重新加载和编辑?

问题描述

我想提供以后可以由用户编辑的模板。因此,它应该是人类可读的 .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.dumps 并放入我的数据库中。直到这里,一切似乎都很好(但我真的认为应该有一种更漂亮的方法来实现这一点?)。

在我用 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)

但我真的一点头绪都没有。本来以为我可以在不使用 lambda 的情况下再次获得 defaultdict,但这会引发错误(TypeError:第一个参数必须是可调用的或无) - 所以我将它设为可调用的......呃......

这样,我得到一个 AttributeError: 'dict' object has no attribute '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 对象中的列表)。

提前致谢

卡尔萨里

标签: pythonjsondictionary

解决方案


我将冒昧地重组您存储模板的方式并提出以下(示例)结构:

{
    "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]]}]})

此代码的目的是概述您要实现的目标,因此如果您要隐藏这些操作并将它们概括为函数和类,请尽量保持此脚本中呈现的流程。


推荐阅读