使用列表构建嵌套数据 class

Build a nested data class with lists

我正在研究 JSON API-调用,我想使用 python 数据 classes 构建它。 由于我是初学者,解决方案可能很麻烦 - 在这种情况下 - 请提出更优雅的解决方案。

所以我希望我的 JSON 请求正文看起来像这样:

{
    "projectFilter": {
        "project": "all",
        "statuses": ["Finished"]
    },
    "currencyId": 0,
    "columns": [
        {"columnType": {
            "kind": "CostActual"
            }
        }
    ]
}

我已将其建模为嵌套数据 class,因此我可以在将来更改 API 调用。 不确定这是否是一个好方法 - 正如我所说 - 初学者。

import json
from dataclasses import dataclass, field
from typing import List, Dict

@dataclass
class _project_filter():
    project : str = 'all'
    statuses : List = field(default_factory=lambda: ['Finished'])

@dataclass
class _column_type():
    columnType : Dict = field(default_factory=lambda: {'kind' : 'CostActual'})

@dataclass
class project():
    projectFilter: _project_filter = _project_filter()
    currencyId : int = NULL
    columns : List[_column_type] = field(default_factory=_column_type)

    def to_json(self):
        return json.dumps(self.__dict__, default=lambda x: x.__dict__, ensure_ascii=False)

调用 .to_json() 方法时得到以下输出:

{
    "projectFilter": {
        "project": "all",
        "statuses": ["Finished"]
    },
    "currencyId": 0,
    "columns": {
        "columnType": {"kind": "CostActual"}
    }
}

如您所见,我没有得到 _column_type 类型的数组。 我认为它会起作用,因为我有 columns : List[_column_type] = field(default_factory=_column_type) 尽管我将字段 columns 指定为 _column_typelist 并且我使用了默认对象,因为我使用了 default_factory 参数。

默认因子只创建一个 _column_type 类型的对象,而不是一个列表。你可以像

那样改变它
@dataclass
class project():
    projectFilter: _project_filter = _project_filter()
    currencyId : int = NULL
    columns : List[_column_type] = field(default_factory=lambda:[_column_type()])

所以使用一个未命名的函数,一个 lambda,创建一个列表,其中包含该类型的单个对象。

附带说明一下,在 Python 中,类 以 Pascal 类型命名,因此 HelloWorld,而不是 hello_world 的蜗牛式命名。

我建议查看 dataclass-wizard 库,因为它看起来非常适合这个用例。

用于序列化目的的默认大小写转换是 camelCase,所以好消息是您不需要传递任何额外的配置来序列化实例时获得所需的结果至 JSON.


我首先将示例 JSON 输入通过管道传输到包含的 CLI utility 以生成数据类模式,并以如下所示的数据类模型结构结束。请注意,我进入并为几个字段添加了默认值,类似于上面的方式。

from __future__ import annotations

from dataclasses import dataclass, field

from dataclass_wizard import JSONWizard


@dataclass
class Project(JSONWizard):
    project_filter: ProjectFilter
    currency_id: int
    columns: list[Column]


@dataclass
class ProjectFilter:
    project: str = 'all'
    statuses: list[str] = field(default_factory=lambda: ['Finished'])


@dataclass
class Column:
    column_type: ColumnType | None = None


@dataclass
class ColumnType:
    kind: str = 'CostActual'

然后我做了一个快速测试以确认我能够使用数据类模式 load/dump JSON 数据:

def main():
    string = """
    {
        "projectFilter": {
            "project": "all"
        },
        "currencyId": 0,
        "columns": [
            {"columnType": {}}
        ]
    }"""

    p = Project.from_json(string)
    print(repr(p))

    print(p.to_json())

    # True
    assert p == p.from_json(p.to_json())


if __name__ == '__main__':
    main()

输出:

Project(project_filter=ProjectFilter(project='all', statuses=['Finished']), currency_id=0, columns=[Column(column_type=ColumnType(kind='CostActual'))])
{"projectFilter": {"project": "all", "statuses": ["Finished"]}, "currencyId": 0, "columns": [{"columnType": {"kind": "CostActual"}}]}