我想将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 orjson  # faster then json =)
from typing import NamedTuple

_j = '{"name":"Иван","age":37,"mother":{"name":"Ольга","age":58},"children":["Маша","Игорь","Таня"],"married": true,' \
     '"dog":null} '


class PersonNameAge(NamedTuple):
    name: str
    age: int


class UserInfo(NamedTuple):
    name: str
    age: int
    mother: PersonNameAge
    children: list
    married: bool
    dog: str


j = orjson.loads(_j)
u = UserInfo(**j)

print(u.name, u.age, u.mother, u.children, u.married, u.dog)

>>> Ivan 37 {'name': 'Olga', 'age': 58} ['Mary', 'Igor', 'Jane'] True None

其他回答

查看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']

就像一本普通的字典。

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

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

这不是代码高尔夫,但这里是我使用类型的最短技巧。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.6或更新版本,你可以看看squema——一个用于静态类型数据结构的轻量级模块。它使您的代码易于阅读,同时提供简单的数据验证,转换和序列化,而无需额外的工作。你可以把它看作是命名元组和数据类的一种更复杂、更有见解的选择。下面是你如何使用它:

from uuid import UUID
from squema import Squema


class FbApiUser(Squema):
    id: UUID
    age: int
    name: str

    def save(self):
        pass


user = FbApiUser(**json.loads(response))
user.save()

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

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

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