我想将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响应位,从一个文件加载:
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字段名。
改进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
如果你使用的是Python 3.5+,你可以使用json来序列化和反序列化到普通的旧Python对象:
import jsons
response = request.POST
# You'll need your class attributes to match your dict keys, so in your case do:
response['id'] = response.pop('user_id')
# Then you can load that dict into your class:
user = jsons.load(response, FbApiUser)
user.save()
你也可以让FbApiUser从jsons继承。JsonSerializable更优雅:
user = FbApiUser.from_json(response)
如果你的类由Python默认类型组成,比如字符串、整数、列表、日期时间等,这些例子就可以工作。不过,jsons lib需要自定义类型的类型提示。
这里有一个快速而肮脏的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()
使用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)