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


当前回答

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

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

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

其他回答

改进lovasoa非常好的答案。

如果你正在使用python 3.6+,你可以使用: PIP安装棉花糖-enum和 PIP安装棉花糖数据类

它简单且类型安全。

你可以在string-json中转换你的类,反之亦然:

从对象到字符串Json:

    from marshmallow_dataclass import dataclass
    user = User("Danilo","50","RedBull",15,OrderStatus.CREATED)
    user_json = User.Schema().dumps(user)
    user_json_str = user_json.data

从String Json到Object:

    json_str = '{"name":"Danilo", "orderId":"50", "productName":"RedBull", "quantity":15, "status":"Created"}'
    user, err = User.Schema().loads(json_str)
    print(user,flush=True)

类定义:

class OrderStatus(Enum):
    CREATED = 'Created'
    PENDING = 'Pending'
    CONFIRMED = 'Confirmed'
    FAILED = 'Failed'

@dataclass
class User:
    def __init__(self, name, orderId, productName, quantity, status):
        self.name = name
        self.orderId = orderId
        self.productName = productName
        self.quantity = quantity
        self.status = status

    name: str
    orderId: str
    productName: str
    quantity: int
    status: OrderStatus

查看JSON模块文档中的专门化JSON对象解码一节。您可以使用它将JSON对象解码为特定的Python类型。

这里有一个例子:

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

import json
def object_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'User':
        return User(obj['name'], obj['username'])
    return obj

json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}',
           object_hook=object_decoder)

print type(User)  # -> <type 'type'>

更新

如果你想通过json模块访问字典中的数据,可以这样做:

user = json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}')
print user['name']
print user['username']

就像一本普通的字典。

因此,我正在寻找一种不需要大量自定义反序列化代码就能解组任意类型(想想数据类的字典,或者数据类数组的字典的字典)的方法。

这是我的方法:

import json
from dataclasses import dataclass, make_dataclass

from dataclasses_json import DataClassJsonMixin, dataclass_json


@dataclass_json
@dataclass
class Person:
    name: str


def unmarshal_json(data, t):
    Unmarhsal = make_dataclass('Unmarhsal', [('res', t)],
                               bases=(DataClassJsonMixin,))
    d = json.loads(data)
    out = Unmarhsal.from_dict({"res": d})
    return out.res


unmarshalled = unmarshal_json('{"1": {"name": "john"} }', dict[str, Person])
print(unmarshalled)

打印:{'1':Person(name='john')}

这不是代码高尔夫,但这里是我使用类型的最短技巧。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)

使用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)