簡介
Web 開發中,一個重要的組成部分便是資料庫了。Web 程式中最常用的莫過於關係型資料庫了,也稱 SQL 資料庫。另外,文件資料庫(如 mongodb)、鍵值對資料庫(如 redis)近幾年也逐漸在 web 開發中流行起來,我們習慣把這兩種資料庫稱為 NoSQL 資料庫。
大多數的關係型資料庫引擎(比如 MySQL、Postgres 和 SQLite)都有對應的 Python 包。在這裡,我們不直接使用這些資料庫引擎提供的 Python 包,而是使用物件關係對映(Object-Relational Mapper, ORM)框架,它將低層的資料庫操作指令抽象成高層的物件導向操作。也就是說,如果我們直接使用資料庫引擎,我們就要寫 SQL 操作語句,但是,如果我們使用了 ORM 框架,我們對諸如表、文件此類的資料庫實體就可以簡化成對 Python 物件的操作。
Python 中最廣泛使用的 ORM 框架是 SQLAlchemy,它是一個很強大的關係型資料庫框架,不僅支援高層的 ORM,也支援使用低層的 SQL 操作,另外,它也支援多種資料庫引擎,如 MySQL、Postgres 和 SQLite 等。
Flask-SQLAlchemy
在 Flask 中,為了簡化配置和操作,我們使用的 ORM 框架是 Flask-SQLAlchemy,這個 Flask 擴充套件封裝了 SQLAlchemy 框架。在 Flask-SQLAlchemy 中,資料庫使用 URL 指定,下表列出了常見的資料庫引擎和對應的 URL。
資料庫引擎 | URL |
---|---|
MySQL | mysql://username:password@hostname/database |
Postgres | postgresql://username:password@hostname/database |
SQLite (Unix) | sqlite:////absolute/path/to/database |
SQLite (Windows) | sqlite:///c:/absolute/path/to/database |
上面的表格中,username 和 password 表示登入資料庫的使用者名稱和密碼,hostname 表示 SQL 服務所在的主機,可以是本地主機(localhost)也可以是遠端伺服器,database 表示要使用的資料庫。有一點需要注意的是,SQLite 資料庫不需要使用伺服器,它使用硬碟上的檔名作為 database。
一個最小的應用
建立資料庫
首先,我們使用 pip 安裝 Flask-SQLAlchemy:
1 |
$ pip install flask-sqlalchemy |
接下來,我們配置一個簡單的 SQLite 資料庫:
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 |
$ cat app.py # -*- coding: utf-8 -*- from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db/users.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db = SQLAlchemy(app) class User(db.Model): """定義資料模型""" __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True) email = db.Column(db.String(120), unique=True) def __init__(self, username, email): self.username = username self.email = email def __repr__(self): return '<User %r>' % self.username |
這裡有幾點需要注意的是:
- app 應用配置項
SQLALCHEMY_DATABASE_URI
指定了 SQLAlchemy 所要操作的資料庫,這裡我們使用的是 SQLite,資料庫 URL 以sqlite:///
開頭,後面的db/users.db
表示資料庫檔案存放在當前目錄的db
子目錄中的users.db
檔案。當然,你也可以使用絕對路徑,如/tmp/users.db
等。 - db 物件是 SQLAlchemy 類的例項,表示程式使用的資料庫。
- 我們定義的
User
模型必須繼承自db.Model
,這裡的模型其實就對應著資料庫中的表。其中,類變數__tablename__
定義了在資料庫中使用的表名,如果該變數沒有被定義,Flask-SQLAlchemy 會使用一個預設名字。
接著,我們建立表和資料庫。為此,我們先在當前目錄建立 db
子目錄和新建一個 users.db
檔案,然後在互動式 Python shell 中匯入 db 物件並呼叫 SQLAlchemy 類的 create_all() 方法:
1 2 3 4 |
$ mkdir db $ python >>> from app import db >>> db.create_all() |
我們驗證一下,”users” 表是否建立成功:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ sqlite3 db/users.db # 開啟資料庫檔案 SQLite version 3.8.10.2 2015-05-20 18:17:19 Enter ".help" for usage hints. sqlite> .schema users # 檢視 "user" 表的 schema CREATE TABLE users ( id INTEGER NOT NULL, username VARCHAR(80), email VARCHAR(120), PRIMARY KEY (id), UNIQUE (username), UNIQUE (email) ); |
插入資料
現在,我們建立一些使用者,通過使用 db.session.add()
來新增資料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@app.route('/adduser') def add_user(): user1 = User('ethan', 'ethan@example.com') user2 = User('admin', 'admin@example.com') user3 = User('guest', 'guest@example.com') user4 = User('joe', 'joe@example.com') user5 = User('michael', 'michael@example.com') db.session.add(user1) db.session.add(user2) db.session.add(user3) db.session.add(user4) db.session.add(user5) db.session.commit() return "<p>add succssfully!" |
這裡有一點要注意的是,我們在將資料新增到會話後,在最後要記得呼叫 db.session.commit()
提交事務,這樣,資料才會被寫入到資料庫。
查詢資料
查詢資料主要是用 query
介面,例如 all()
方法返回所有資料,filter_by()
方法對查詢結果進行過濾,引數是鍵值對,filter
方法也可以對結果進行過濾,但引數是布林表示式,詳細的介紹請檢視這裡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
>>> from app import User >>> users = User.query.all() >>> users [<User u'ethan'>, <User u'admin'>, <User u'guest'>, <User u'joe'>, <User u'michael'>] >>> >>> user = User.query.filter_by(username='joe').first() >>> user <User u'joe'> >>> user.email u'joe@example.com' >>> >>> user = User.query.filter(User.username=='ethan').first() >>> user <User u'ethan'> |
如果我們想檢視 SQLAlchemy 為查詢生成的原生 SQL 語句,只需要把 query 物件轉化成字串:
1 2 |
>>> str(User.query.filter_by(username='guest')) 'SELECT users.id AS users_id, users.username AS users_username, users.email AS users_email \nFROM users \nWHERE users.username = :username_1' |
分頁方法
分頁方法可以採用 limit()
和 offset()
方法,比如從第 3 條記錄開始取(注意是從 0 開開始算起),並最多取 1 條記錄,可以這樣:
1 |
users = User.query.limit(1).offset(3) |
更新資料
更新資料也用 add()
方法,如果存在要更新的物件,SQLAlchemy 就更新該物件而不是新增。
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> from app import db >>> from app import User >>> >>> admin = User.query.filter_by(username='admin').first() >>> >>> admin.email = 'admin@hotmail.com' >>> db.session.add(admin) >>> db.session.commit() >>> >>> admin = User.query.filter_by(username='admin').first() >>> admin.email u'admin@hotmail.com' |
刪除資料
刪除資料用 delete()
方法,同樣要記得 delete
資料後,要呼叫 commit()
提交事務:
1 2 3 4 5 6 |
>>> from app import db >>> from app import User >>> >>> admin = User.query.filter_by(username='admin').first() >>> db.session.delete(admin) >>> db.session.commit() |
本文完整的程式碼可在這裡下載。