數據庫就是有組織的存儲應用程序數據,而後查詢檢索指定須要的那部分。大部分web應用程序都採用基於關係模型的數據庫,也稱做結構化查詢語言(SQL)數據庫。可是最近幾年面向文檔數據庫和鍵值數據庫(一般稱做NoSQL數據庫),成爲很是流行的替代者。我的推薦《七週七數據庫》這本書,它對各類類型的數據庫、應用場景和多種不一樣類型數據庫配合使用有比較好的講解。python
關係數據庫將數據保存在表中來模擬應用程序中不一樣的實體。例如,一個訂單管理應用程序數據庫可能會有customers、products和orders表。git
一個表有一個固定數量的列和一個可變的行數。列定義了數據表所表明的實體的屬性。例如,customers表會有name、address、phone等列。表中的每一行定義了由全部列的值組成的實際數據元素。github
表有種特殊列稱做主鍵,它持有一個唯一的標識符爲表中存儲的每一行。表也能夠有外鍵,用於引用其餘表的主鍵。這些行之間的鏈接稱做關係,也是關係數據庫模型的基礎。web
圖像5-1展現了存儲users和roles表的簡單數據庫圖。鏈接兩個表的線表明兩個表之間的關係。sql
圖像5-1. 關係數據庫示例數據庫
在這個數據庫表中,roles表存儲了一組全部可能的用戶角色,每個都被定義爲惟一id值——也是表的主鍵。users表包含一組用戶,一樣每個都有惟一id值。除了主鍵id,roles表還有name列,而users表還有username和password列。在users表中的role_id列是一個引用role表中id列的外鍵,以這種方式確立分配給每一個用戶的角色。flask
就像這個示例中看到的那樣,關係數據庫存儲數據高效且避免重複。重命名用戶角色在這個數據庫中會變得異常簡單,由於角色名保存在單獨的地方。當roles表中的角色名發生改變,全部用戶持有的role_id引用的角色會當即看到這些變化。後端
而另外一方面,將數據拆分到多個表中則會變得更加複雜。生成一組用戶及其角色會產生一個小問題,由於用戶和用戶角色須要從兩張表中讀,且只有鏈接後才能一塊兒出現。當須要的時候關係數據庫引擎會提供支持來執行兩個表的鏈接操做。服務器
與上一節描述相反的、非關係模型的數據庫被統稱爲NoSQL數據庫。NoSQL數據庫常見的組織方式是使用collections代替表、documents代替記錄。NoSQL數據庫的設計方式使得鏈接會很複雜,因此大部分都不支持這個操做。圖像5-1若是用NoSQL數據庫結構來表達則是這樣的:列出用戶及他們的角色,須要應用程序本身經過讀取每一個用戶的role_id字段去執行鏈接操做,而後查找roles表。app
圖像5-2展現了更接近NoSQL數據庫的設計思想。這個操做運用了一個被稱爲反模式的思想,減小了表的數量卻增長了重複數據。
圖像5-2. NoSQL數據庫示例
這種結構的數據庫爲每一個用戶顯式的存儲用戶角色名。重命名角色名絕對是一項昂貴的操做,可能須要更新大量的文檔。
但對於NoSQL數據庫這並不都是壞消息。雖然有重複的數據,可是查詢速度快,由於不須要鏈接,能夠直接列出用戶和他們的角色。
SQL數據庫擅長以高效、緊湊的形式存儲結構化數據。這些數據庫不遺餘力保持一致性。NoSQL數據庫會放低一些一致性要求,所以在性能上有更大的優點。
全面分析和比較數據庫類型已經超出了本教程的範圍。對於中小型應用程序SQL數據庫和NoSQL數據庫徹底能夠勝任,且性能幾乎差很少。
Python有大部分的數據庫引擎包,包括開源的和商業的。Flask在可以使用的數據庫包上沒有限制,因此你可使用MySQL、Postgres、SQLite、Redis、MongoDB或者CouchDB中你喜歡的任何一個。
若是這些還不夠,也有大量的數據庫抽象層包,如SQLAlchemy或MongoEngine讓你像操做常規Python對象那樣,而不是數據庫實體表、文檔或查詢語句。
在選擇數據庫框架的時候須要評估許多因素:
易用性
若是直接比較數據庫引擎和數據庫抽象層,第兩者明顯勝出。抽象層又稱做對象關係映射(ORM)或對象文檔映射(ODM),提供從高級面向對象操做到底層數據庫指令的透明轉換。
性能
ORM和ODM的轉化須要從對象域轉化爲數據庫域,因此會有一些開銷。大多數狀況下,性能損耗是微不足道的,但總有例外。通常來講,ORM和ODM得到的生產力遠遠超過了性能降低的那部分,因此這不是一個有效的論點來徹底拋棄ORM和ODM。應該關心的是選擇怎樣的數據庫抽象層,提供可訪問底層數據庫中特定操做,就像本地數據庫指令那樣實現的抽象層最佳。
可移植性
數據庫的選擇必須考慮開發和生產平臺。例如,若是你計劃在雲主機上託管應用程序,那麼你應該找出提供該服務的數據庫。
另外一方面ORM和ODM的可移植性不錯。儘管一些框架只爲單個數據庫引擎提供抽象層,有些抽象層更高級,能夠選擇哪一種數據庫引擎且訪問使用的是同一個面向對象的接口。最好的例子就是SQLAlchemy ORM,支持一組關係數據庫引擎,包括流行的MySQL、Postgres和SQLite。
Flask集成
選擇一個集成了Flask的框架並非必須的,可是能夠不用本身寫集成代碼。Flask集成能夠簡化配置和操做,因此應該優先使用專門設計的Flask擴展包。
基於這些目的,Flask-SQLAlchemy將是本書示例中應該選擇的數據庫框架,它對SQLAlchemy進行了封裝。
Flask-SQLAlchemy是一個Flask擴展,它簡化了在Flask應用程序中對SQLAlchemy的使用。SQLAlchemy是一個強大的關係數據庫框架,支持一些數據庫後端。提供高級的ORM和底層訪問數據庫的本地SQL功能。
和其餘擴展同樣,經過pip安裝Flask-SQLAlchemy:
(venv) $ pip install flask-sqlalchemy
在Flask-SQLAlchemy,數據庫被指定爲URL。表格5-1列出三個最受歡迎的數據庫引擎url的格式。
表格5-1. Flask-SQLAlchemy數據URLs
在這些URL中,hostname是指託管MySQL服務的服務器,多是本地(localhost)又或是遠程服務器。數據庫服務器能夠託管多個數據庫,因此database指出要使用的數據庫名。數據庫須要身份驗證,username和 password是數據庫用戶憑證。
注:> SQLite數據庫沒有服務,因此hostname、username和password能夠缺省且數據庫是一個磁盤文件名。
應用程序數據庫URL必須在Flask配置對象中的SQLALCHEMY_DATABASE_URI鍵中進行配置。另外一個有用的選項是SQLALCHEMY_COMMIT_ON_TEARDOWN,能夠設置爲True來啓用自動提交數據庫更改在每一個請求中。查閱Flask-SQLAlchemy文檔獲取更多其餘配置選項。示例5-1展現如何初始化並配置簡單的SQLite數據庫。
示例5-1. hello.py:數據庫配置
from flask.ext.sqlalchemy import SQLAlchemy basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, 'data.sqlite') app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True db = SQLAlchemy(app)
由SQLAlchemy
實例化的db
對象表示數據庫且提供訪問Flask-SQLAlchemy的全部功能。
模型是指由應用程序使用的持久化實體。在ORM的背景下,一個模型一般是一個帶有屬性的Python類,其屬性與數據庫表的列相匹配對應。Flask-SQLAlchemy數據庫實例提供了一個基類以及一組輔助類和函數用於定義它的結構。表格5-1中的roles表和users表能夠定義爲Role模型和User模型如示例5-2所示。
示例5-2.hello.py:Role模型和User模型定義
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) def __repr__(self): return '<Role %r>' % self.name class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) def __repr__(self): return '<User %r>' % self.username
__tablename__
類變量定義數據庫中表的名稱。若是__tablename__
缺省Flask-SQLAlchemy會指定默認的表名,可是這些缺省名稱不遵照使用複數命名的約定,因此最好是顯式命名錶名。其他的變量是模型的屬性,被定義爲db.Column
類的實例。
傳給db.Column
構造函數的第一個參數是數據庫列的類型也就是模型屬性的數據類型。表格5-2列出一些可用的列的類型,也是用於模型中的Python類型。
表格5-2. 最多見的SQLAlchemy列類型
db.Column
剩餘的參數爲每一個屬性指定了配置選項。表格5-3列出一些可用的選項。
表格5-3. 最多見的SQLAlchemy列選項
注:Flask-SQLAlchemy須要給全部的模型定義主鍵列,一般命名爲id。
兩個模型都包含了repr()
方法來給它們顯示一個可讀字符串,雖然不是徹底必要,不過用於調試和測試仍是很不錯的。