我想将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对象,是不是会更好?


当前回答

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

其他回答

这里有一个快速而肮脏的json pickle替代方案

import json

class User:
    def __init__(self, name, username):
        self.name = name
        self.username = username

    def to_json(self):
        return json.dumps(self.__dict__)

    @classmethod
    def from_json(cls, json_str):
        json_dict = json.loads(json_str)
        return cls(**json_dict)

# example usage
User("tbrown", "Tom Brown").to_json()
User.from_json(User("tbrown", "Tom Brown").to_json()).to_json()

你可以试试这个:

class User(object):
    def __init__(self, name, username):
        self.name = name
        self.username = username

import json
j = json.loads(your_json)
u = User(**j)

只需创建一个新对象,并将参数作为映射传递。


你也可以有一个带有对象的JSON:

import json
class Address(object):
    def __init__(self, street, number):
        self.street = street
        self.number = number

    def __str__(self):
        return "{0} {1}".format(self.street, self.number)

class User(object):
    def __init__(self, name, address):
        self.name = name
        self.address = Address(**address)

    def __str__(self):
        return "{0} ,{1}".format(self.name, self.address)

if __name__ == '__main__':
    js = '''{"name":"Cristian", "address":{"street":"Sesame","number":122}}'''
    j = json.loads(js)
    print(j)
    u = User(**j)
    print(u)

使用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响应位,从一个文件加载:

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def load_data(file_name):
  with open(file_name, 'r') as file_data:
    return file_data.read().replace('\n', '')
def json2obj(file_name): return json.loads(load_data(file_name), object_hook=_json_object_hook)

有一点:它不能加载前面有数字的项目。是这样的:

{
  "1_first_item": {
    "A": "1",
    "B": "2"
  }
}

因为“1_first_item”不是一个有效的python字段名。

这不是代码高尔夫,但这里是我使用类型的最短技巧。SimpleNamespace作为JSON对象的容器。

与namedtuple解决方案相比,它是:

可能更快/更小,因为它没有为每个对象创建一个类 更短的 没有重命名选项,对于不是有效标识符的键可能有相同的限制(在幕后使用setattr)

例子:

from __future__ import print_function
import json

try:
    from types import SimpleNamespace as Namespace
except ImportError:
    # Python 2.x fallback
    from argparse import Namespace

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

x = json.loads(data, object_hook=lambda d: Namespace(**d))

print (x.name, x.hometown.name, x.hometown.id)