我想将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 str和dict之间来回转换,我已经从我的答案复制到另一个问题:

import json

class PyJSON(object):
    def __init__(self, d):
        if type(d) is str:
            d = json.loads(d)

        self.from_dict(d)

    def from_dict(self, d):
        self.__dict__ = {}
        for key, value in d.items():
            if type(value) is dict:
                value = PyJSON(value)
            self.__dict__[key] = value

    def to_dict(self):
        d = {}
        for key, value in self.__dict__.items():
            if type(value) is PyJSON:
                value = value.to_dict()
            d[key] = value
        return d

    def __repr__(self):
        return str(self.to_dict())

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
        return self.__dict__[key]

json_str = """... JSON string ..."""

py_json = PyJSON(json_str)

其他回答

对于复杂的对象,可以使用JSON Pickle

Python库,用于将任意对象图序列化为JSON。 它几乎可以接受任何Python对象并将对象转换为JSON。 此外,它还可以将对象重新构造回Python。

我已经编写了一个名为any2any的小型(反)序列化框架,它可以帮助在两种Python类型之间进行复杂的转换。

在您的情况下,我猜您想从字典(通过json.loads获得)转换为复杂的对象response.education;Response.name,具有嵌套结构response.education.id,等等… 这就是这个框架的用途。文档还不是很好,但是通过使用any2any.simple。MappingToObject,你应该可以很容易地做到。如果需要帮助,请询问。

你可以使用

x = Map(json.loads(response))
x.__class__ = MyClass

在哪里

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v
                    if isinstance(v, dict):
                        self[k] = Map(v)

        if kwargs:
            # for python 3 use kwargs.items()
            for k, v in kwargs.iteritems():
                self[k] = v
                if isinstance(v, dict):
                    self[k] = Map(v)

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

对于通用的、经得起未来考验的解决方案。

使用python 3.7,我发现下面的代码非常简单有效。在本例中,将JSON从文件加载到字典中:

class Characteristic:
    def __init__(self, characteristicName, characteristicUUID):
        self.characteristicName = characteristicName
        self.characteristicUUID = characteristicUUID


class Service:
    def __init__(self, serviceName, serviceUUID, characteristics):
        self.serviceName = serviceName
        self.serviceUUID = serviceUUID
        self.characteristics = characteristics

class Definitions:
    def __init__(self, services):
        self.services = []
        for service in services:
            self.services.append(Service(**service))


def main():
    parser = argparse.ArgumentParser(
        prog="BLEStructureGenerator",
        description="Taking in a JSON input file which lists all of the services, "
                    "characteristics and encoded properties. The encoding takes in "
                    "another optional template services and/or characteristics "
                    "file where the JSON file contents are applied to the templates.",
        epilog="Copyright Brown & Watson International"
    )

    parser.add_argument('definitionfile',
                        type=argparse.FileType('r', encoding='UTF-8'),
                        help="JSON file which contains the list of characteristics and "
                             "services in the required format")
    parser.add_argument('-s', '--services',
                        type=argparse.FileType('r', encoding='UTF-8'),
                        help="Services template file to be used for each service in the "
                             "JSON file list")
    parser.add_argument('-c', '--characteristics',
                        type=argparse.FileType('r', encoding='UTF-8'),
                        help="Characteristics template file to be used for each service in the "
                             "JSON file list")

    args = parser.parse_args()
    definition_dict = json.load(args.definitionfile)
    definitions = Definitions(**definition_dict)

扩展一下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)