前面幾個章節介紹了怎樣搭建flask伺服器,介紹了flask中如何實現HTTP的4種操作方法,但是前一章中是使用記憶體來儲存資料,這樣資料實際沒有儲存下來,而且也只能在單程式中使用,實際使用中我們需要資料庫來為我們完成資料的相關操作,這一章將介紹如何在flask中使用資料庫,以mysql為例;
flask有一個對資料庫的擴充套件flask-sqlalchemy,它簡化了在flask中對sqlalchemy的操作,sqlalchemy是一個強大的關聯式資料庫框架,支援一些資料庫後端,提供高階的ORM和底層訪問資料庫的本地sql功能;
使用pip來安裝flask-sqlalchemy
1 |
pip install flask-sqlalchemy |
在flask-sqlalchemy中,sql被指定為URL,訪問mysql的url如下:
1 |
mysql://username:[email protected]/database |
在URL中hostname是指託管mysql服務的伺服器,可以使localhost也可以是遠端伺服器,資料庫伺服器可以託管多個資料庫,所以database要指定連線的資料庫名,username和password是資料庫的身份驗證;
應用程式資料庫URL必須在flask配置物件中的SQLALCHEMY_DATABASE_URI中進行配置,另一個有用的選項是SQLALCHEMY_COMMIT_ON_TEARDOWN,可以設定為True來啟動自動提交資料庫更改在每個請求中:
1 2 3 4 5 6 7 8 9 10 11 |
from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy import config databaseurl = 'mysql://%s:%s@%s:%s/%s' % (config.MYSQL_USER, config.MYSQL_PASS, config.MYSQL_HOST, config.MYSQL_PORT, config.MYSQL_DB) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = databaseurl app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app) |
由SQLAlchemy例項化的db物件表示資料庫且提供訪問flask-sqlalchemy的所有功能;
flask_sqlalchemy使用模型來定義資料庫表,一個模型通常是一個帶有屬性的python類,其屬性與資料庫表的列相匹配對應,flask-sqlalchemy資料庫例項提供了一個基類以及一組輔助類和函式用於定義它的結構,如下定義了一個student模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class student(db.Model): __tablename__ = 'student' id = db.Column(db.Integer, primary_key=True, nullable=False) name = db.Column(db.String(20), nullable=False) age = db.Column(db.Integer, nullable=False) def __init__(self, id, name, age): self.id = id self.name = name self.age = age def __repr__(self): return '' % (self.id, self.name) |
__tablename__類變數定義資料庫中表的名稱,如果預設,flask_sqlalchemy會指定預設表名,其餘的變數是模型的屬性,定義為db.Column類的例項;
傳給db.Column建構函式的第一個引數是資料庫列的型別也就是模型屬性的資料型別:
型別名稱 | python型別 | 描述 |
Integer | int | 常規整型,通常為32位 |
SmallInteger | int | 短整型,通常為16位 |
BigInteger | int或long | 精度不受限整型 |
Float | float | 浮點型 |
Numeric | decimal | 定點數 |
String | str | 可變長度字串 |
Text | str | 可變長度字串,適合大量文字 |
Unicode | unicode | 可變長度Unicode字串 |
Boolean | bool | 布林值 |
Date | datetime.date | 日期型別 |
Time | datetime.time | 時間型別 |
Daetime | datetime.datetime | 日期時間型別 |
Interval | datetime.timedate | 時間間隔 |
Enum | str | 字元列表 |
PickleType | 任意Python物件 | 自動Pickle序列化 |
LargeBinary | str | 二進位制 |
其它的引數為每個屬性指定了配置選項:
可選引數 | 描述 |
primary_key | 設定為True,該列為表的主鍵 |
unique | 設定為True,該列不允許相同的值 |
index | 設定為True,為該列建立索引 |
nullable | 設定為True,允許為空 |
default | 定義該列的預設值 |
一個簡單的例子,使用POST插入學生資訊,使用GET來獲取資訊:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
from flask import Flask from flask import request from flask import jsonify from flask.ext.sqlalchemy import SQLAlchemy import config databaseurl = 'mysql://%s:%s@%s:%s/%s' % (config.MYSQL_USER, config.MYSQL_PASS, config.MYSQL_HOST, config.MYSQL_PORT, config.MYSQL_DB) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = databaseurl app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app) class mytable(db.Model): id = db.Column(db.Integer, primary_key=True, nullable=False) name = db.Column(db.String(20), nullable=False) age = db.Column(db.Integer, nullable=False) def __init__(self, id, name, age): self.id = id self.name = name self.age = age def __repr__(self): return '' % (self.id, self.name) db.create_all() @app.route('/', methods=['POST']) def hello(): if not request.json: return "failed!", 400 student = { 'id': request.json['id'], 'name': request.json['name'], 'age': request.json['age'] } #初始化student物件 stu = mytable(int(student['id']), student['name'], int(student['age'])) #將新增專案插入資料庫 db.session.add(stu) #提交修改 db.session.commit() return "Hello World!" @app.route('/', methods=['GET']) def get_one(): if not request.args['id']: abort(400) get_id = request.args['id'] #得到表中所有的資料 ids = mytable.query.all() #使用filter找到指定專案 get = mytable.query.filter_by(id = get_id).first() #獲取表成員屬性 ret = 'id=%d,name=%s,age=%d' % (get.id, get.name, get.age) return ret app.run(debug = True) |
使用post上傳資訊後,資料或同步儲存到資料庫中,程式重啟後依然能夠從資料庫中獲取歷史資訊;