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


当前回答

这不是一个很难的事情,我看到上面的答案,他们中的大多数在“列表”中有一个性能问题

这段代码比上面的代码快得多

import json 

class jsonify:
    def __init__(self, data):
        self.jsonify = data

    def __getattr__(self, attr):
        value = self.jsonify.get(attr)
        if isinstance(value, (list, dict)):
            return jsonify(value)
        return value

    def __getitem__(self, index):
        value = self.jsonify[index]
        if isinstance(value, (list, dict)):
            return jsonify(value)
        return value

    def __setitem__(self, index, value):
        self.jsonify[index] = value

    def __delattr__(self, index):
        self.jsonify.pop(index)

    def __delitem__(self, index):
        self.jsonify.pop(index)

    def __repr__(self):
        return json.dumps(self.jsonify, indent=2, default=lambda x: str(x))

exmaple

response = jsonify(
    {
        'test': {
            'test1': [{'ok': 1}]
        }
    }
)
response.test -> jsonify({'test1': [{'ok': 1}]})
response.test.test1 -> jsonify([{'ok': 1}])
response.test.test1[0] -> jsonify({'ok': 1})
response.test.test1[0].ok -> int(1)

其他回答

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

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

如果你正在使用python 3.6+,你可以使用棉花糖-数据类。与上面列出的所有解决方案相反,它既简单,又类型安全:

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

user = User.Schema().load({"name": "Ramirez"})

这里有一个快速而肮脏的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()

这不是一个很难的事情,我看到上面的答案,他们中的大多数在“列表”中有一个性能问题

这段代码比上面的代码快得多

import json 

class jsonify:
    def __init__(self, data):
        self.jsonify = data

    def __getattr__(self, attr):
        value = self.jsonify.get(attr)
        if isinstance(value, (list, dict)):
            return jsonify(value)
        return value

    def __getitem__(self, index):
        value = self.jsonify[index]
        if isinstance(value, (list, dict)):
            return jsonify(value)
        return value

    def __setitem__(self, index, value):
        self.jsonify[index] = value

    def __delattr__(self, index):
        self.jsonify.pop(index)

    def __delitem__(self, index):
        self.jsonify.pop(index)

    def __repr__(self):
        return json.dumps(self.jsonify, indent=2, default=lambda x: str(x))

exmaple

response = jsonify(
    {
        'test': {
            'test1': [{'ok': 1}]
        }
    }
)
response.test -> jsonify({'test1': [{'ok': 1}]})
response.test.test1 -> jsonify([{'ok': 1}])
response.test.test1[0] -> jsonify({'ok': 1})
response.test.test1[0].ok -> int(1)

更新

在Python3中,你可以使用SimpleNamespace和object_hook在一行中完成:

import json
from types import SimpleNamespace

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

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
print(x.name, x.hometown.name, x.hometown.id)

旧答案(Python2)

在Python2中,你可以使用namedtuple和object_hook在一行中完成(但对于嵌套对象非常慢):

import json
from collections import namedtuple

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

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id

或者,为了便于重用:

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)

x = json2obj(data)

如果希望它处理不是很好的属性名称的键,请检查namedtuple的rename参数。