Sqlalchemy 可以很方便地做ORMapping,把資料庫記錄對映為業務實體類的例項,例如下面這樣:
class Student(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))
if __name__ == '__main__':
student = Student.query.get(1)
但這種例項不方便序列化,比如要想在 Flask Web Service 介面中返回這個物件:
@app.route('/demo/db', methods=['GET'])
def demo_db():
student = Student.query.get(1)
return jsonify(student)
或者是直接轉 JSON 字串:
import json
json.dumps(student)
都會報錯:Object of type Student is not JSON serializable
。
在網上搜的話,會有五花八門的答案,大部分都是讓你實現某個類似 to_json 的方法,有些根本不管用,有些很麻煩。
其實最簡單的解決方案就是:
用 python 3.7 引入的 dataclass
裝飾器,這個裝飾器幫我們實現了對應的方法,可以直接把類變數宣告當做例項變數的定義:
from dataclasses import dataclass
@dataclass
class Student(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)
就不會報錯了,但奇怪的是,結果是個空物件:{}
。
原來 dataclass 裝飾器“認可”的欄位宣告,必須有 type annotation,改成下面這樣:
from dataclasses import dataclass
@dataclass
class Student(db.Model):
id: int = db.Column(db.Integer, primary_key=True)
name: str = db.Column(db.String(100))
city: str = db.Column(db.String(50))
addr: 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:
import json
from dataclasses import dataclass
print(json.dumps(dataclasses.asdict(student)))