问题Sqlalchemy可以很方便的做ORMapping,将数据库记录映射到业务实体类的实例,例如如下:classStudent(db.Model):id=db.Column(db.整数,primary_key=True)name=db.Column(db.String(100))city=db.Column(db.String(50))addr=db.Column(db.String(200))pin=db.Column(db.String(10))if__name__=='__main__':student=Student.query.get(1)但是这种实例不方便序列化。例如,如果你想在FlaskWeb服务接口中返回这个对象:@app.route('/demo/db',methods=['GET'])defdemo_db():student=Student.query.get(1)返回jsonify(student)或者直接转换JSON字符串:importjsonjson.dumps(student)会报错:ObjectoftypeStudentisnotJSONserializable。如果在网上搜索方法,会有五花八门的答案,大部分都是让你自己实现一个类似to_json的方法,有的根本不行,有的很麻烦。其实最简单的方案是:dataclass使用python3.7引入的dataclass装饰器。这个装饰器帮助我们实现了相应的方法,我们可以直接使用类变量声明作为实例变量的定义:fromdataclassesimportdataclass@dataclassclassStudent(db.Model):id=db.Column(db.Integer,primary_key=True)name=db.Column(db.String(100))city=db.Column(db.String(50))addr=db.Column(db.String(200))pin=db.Column(db.String(10))这时候调用jsonify(student)不会报错,但是奇怪的是结果是一个空对象:{}。数据类装饰器“识别”的原始字段声明必须具有类型注释,应更改为以下内容:fromdataclassesimportdataclass@dataclassclassStudent(db.Model):id:int=db.Column(db.Integer,primary_key=True)名称:str=db.Column(db.String(100))城市:str=db.Column(db.String(50))地址:str=db.Column(db.String(200))pin:str=db.Column(db.String(10))的输出是完美的:{addr:"xxx",city:"bj",id:1,name:"hui",pin:"xyz"}但是jsonify可用,json.dumps还是会报错。最简单的方法是先将对象转成dict,再转成json:依赖于直接类属性定义,无法获取到父类中的定义,所以像下面的代码:=True)@dataclassclassStudent(BaseObj):姓名:str=db.Column(db.String(100))城市:str=db.Column(db.String(50))地址:str=db.Column(db.字符串(200))引脚:str=db.Column(db.String(10))if__name__=='__main__':student=Student.query.get(1)print(json.dumps(dataclasses.asdict(student)))会找到输出结果中,如果缺少id字段,又不引入第三方库,很难通过简洁的代码实现。这里推荐一个小库:objtyping,可以转换为任意实例对象(不需要是dataclass或者其他任何装饰)。基本类型的dict、list或dict-list嵌套结构支持多级嵌套。首先安装依赖:pipinstallobjtyping,所以上面的Student对象可以这样转换:fromobjtypingimportto_primitivestudent=Student.query.get(1)print(json.dumps(to_primitive(student)))你可以看到在输出结果,包括id字段。结语一句话总结:如果是python3.7以上的环境,不关心加dataclass装饰器,数据对象实例之间没有继承关系,就用dataclass方法;如果数据对象定义包含继承关系,或者是老系统,不想添加,使用objtyping三方库。
