这肯定是个老生常谈的问题,在此记录下。
在Python中,当在我们使用sqlalchemy.orm来对数据库对象进行存取,并将这些数据展现到前台页面时,我们就面临如何将Python中的类对象进行JSON序列化。
简单起见,我们从代码说起:
首先,我们定义一个用户类,用以存储用户信息
class User(object):
def __init__(self, id, name, password):
self.__id = id
self.__name = name
self.__password = password
def __repr__(self):
return "id is %s, name is %s, password is %s" % (self.__id, self.__name, self.__password)
def get_name(self):
return self.__name
def get_password(self):
return self.__password
def get_id(self):
return self.__id
实例化一个用户对象user1,并直接进行JSON序列化dumps操作
user1 = User(1, 'test', 'password')
print(user1)
# 直接序列化
print(json.dumps(user1))
得到报错信息:
TypeError: Object of type ‘User’ is not JSON serializable
User对象无法直接序列化,看下dumps方法的定义:
def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
注意,default参数定义如下:
default(obj)
is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
因此,我们给User对象指定一个序列化方法:
def user_to_str(user):
return {'id': user.get_id(), 'name': user.get_name(), 'password': user.get_password()}
重新执行dumps方法,我们得到如下结果:
{“id”: 1, “name”: “test”, “password”: “password”}
当然,在Python中_dict_是一个特殊的属性,其包含了类的所有属性,因此,我们还可以给User对象指定如下参数
json.dumps(user1, default=lambda obj: obj.dict)
重新运行,我们得到如下结果:
{“_User__id”: 1, “_User__name”: “test”, “_User__password”: “password”}
假设我们重新定义一个Teacher类,如下:
class Teacher(object):
__slots__ = ('address', 'grade')
def __repr__(self):
address = None
grade = None
if hasattr(self, 'address'):
address = self.address
if hasattr(self, 'grade'):
grade = self.grade
return "address is %s, grade is %s" % (address, grade)
注意,与User类略有不同的是,我们通过_slots_内置属性限制了对象Teacher只具备address和grade属性,我们重新运行方法
json.dumps(teacher, default=lambda obj: obj.dict)
得到报错信息:
AttributeError: ‘Teacher’ object has no attribute ‘dict’
使用_slots_限制的类不具备_dict_属性,因此,我们还需要自定实现Teacher类的JSON序列化方法
def teacher_to_str(teacher):
address = ''
grade = ''
if hasattr(teacher, 'address'):
address = teacher.address
if hasattr(teacher, 'grade'):
grade = teacher.grade
return {'address': address, 'grade': grade}