我想将JSON数据转换为Python对象。

我从Facebook API收到JSON数据对象,我想将其存储在数据库中。

我的当前视图在Django (Python)(请求。POST包含JSON):

response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()

这很好,但是如何处理复杂的JSON数据对象呢? 如果我能以某种方式将这个JSON对象转换为易于使用的Python对象,是不是会更好?


当前回答

这里给出的答案没有返回正确的对象类型,因此我在下面创建了这些方法。如果你试图向给定JSON中不存在的类中添加更多字段,它们也会失败:

def dict_to_class(class_name: Any, dictionary: dict) -> Any:
    instance = class_name()
    for key in dictionary.keys():
        setattr(instance, key, dictionary[key])
    return instance


def json_to_class(class_name: Any, json_string: str) -> Any:
    dict_object = json.loads(json_string)
    return dict_to_class(class_name, dict_object)

其他回答

我认为最简单的解决方法是

import orjson  # faster then json =)
from typing import NamedTuple

_j = '{"name":"Иван","age":37,"mother":{"name":"Ольга","age":58},"children":["Маша","Игорь","Таня"],"married": true,' \
     '"dog":null} '


class PersonNameAge(NamedTuple):
    name: str
    age: int


class UserInfo(NamedTuple):
    name: str
    age: int
    mother: PersonNameAge
    children: list
    married: bool
    dog: str


j = orjson.loads(_j)
u = UserInfo(**j)

print(u.name, u.age, u.mother, u.children, u.married, u.dog)

>>> Ivan 37 {'name': 'Olga', 'age': 58} ['Mary', 'Igor', 'Jane'] True None

JSON到python对象

下面的代码递归地使用对象键创建动态属性。

JSON对象- fb_data.json:

{
    "name": "John Smith",
    "hometown": {
        "name": "New York",
        "id": 123
    },
    "list": [
        "a",
        "b",
        "c",
        1,
        {
            "key": 1
        }
    ],
    "object": {
        "key": {
            "key": 1
        }
    }
}

在转换中我们有三种情况:

列表 Dicts(新对象) Bool, int, float和STR

import json


class AppConfiguration(object):
    def __init__(self, data=None):
        if data is None:
            with open("fb_data.json") as fh:
                data = json.loads(fh.read())
        else:
            data = dict(data)

        for key, val in data.items():
            setattr(self, key, self.compute_attr_value(val))

    def compute_attr_value(self, value):
        if isinstance(value, list):
            return [self.compute_attr_value(x) for x in value]
        elif isinstance(value, dict):
            return AppConfiguration(value)
        else:
            return value


if __name__ == "__main__":
    instance = AppConfiguration()

    print(instance.name)
    print(instance.hometown.name)
    print(instance.hometown.id)
    print(instance.list[4].key)
    print(instance.object.key.key)

键值对是属性-对象。

输出:

John Smith
New York
123
1
1

将JSON作为代码粘贴

支持TypeScript、Python、Go、Ruby、c#、Java、Swift、Rust、Kotlin、c++、Flow、Objective-C、JavaScript、Elm、JSON Schema。

从JSON、JSON Schema和TypeScript中交互式地生成类型和(反)序列化代码 将JSON/JSON Schema/TypeScript作为代码粘贴

quicktype从示例JSON数据中推断类型,然后输出强类型模型和序列化器,以便用所需的编程语言处理这些数据。

输出:

# Generated by https://quicktype.io
#
# To change quicktype's target language, run command:
#
#   "Set quicktype target language"

from typing import List, Union


class Hometown:
    name: str
    id: int

    def __init__(self, name: str, id: int) -> None:
        self.name = name
        self.id = id


class Key:
    key: int

    def __init__(self, key: int) -> None:
        self.key = key


class Object:
    key: Key

    def __init__(self, key: Key) -> None:
        self.key = key


class FbData:
    name: str
    hometown: Hometown
    list: List[Union[Key, int, str]]
    object: Object

    def __init__(self, name: str, hometown: Hometown, list: List[Union[Key, int, str]], object: Object) -> None:
        self.name = name
        self.hometown = hometown
        self.list = list
        self.object = object

这个扩展可以在Visual Studio代码市场中免费获得。

这是我的办法。

特性

支持类型提示 如果缺少键则引发错误。 跳过数据中的额外值

import typing

class User:
    name: str
    age: int

    def __init__(self, data: dict):
        for k, _ in typing.get_type_hints(self).items():
            setattr(self, k, data[k])

data = {
    "name": "Susan",
    "age": 18
}

user = User(data)
print(user.name, user.age)

# Output: Susan 18
def load_model_from_dict(self, data: dict):
    for key, value in data.items():
        self.__dict__[key] = value
    return self

它帮助返回你自己的模型,从字典中不可预见的变量。

扩展一下DS的答案,如果你需要对象是可变的(而namedtuple不是),你可以使用记录类库而不是namedtuple:

import json
from recordclass import recordclass

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse into a mutable object
x = json.loads(data, object_hook=lambda d: recordclass('X', d.keys())(*d.values()))

修改后的对象可以使用simplejson很容易地转换回json:

x.name = "John Doe"
new_json = simplejson.dumps(x)