從零開(kāi)始用 Flask 搭建一個(gè)網(wǎng)站(一) 介紹了如何搭建 Python 環(huán)境,以及 Flask 應(yīng)用基本項(xiàng)目結(jié)構(gòu)。我們要搭建的網(wǎng)站是管理第三方集成的控制臺(tái),類似于 Slack。 今天主要講解數(shù)據(jù)如何在 Flask 應(yīng)用中流動(dòng),其它的框架基本上也是大同小異。
數(shù)據(jù)庫(kù)
既然是數(shù)據(jù)的流動(dòng),首先要建立起存取數(shù)據(jù)的地方,也就是數(shù)據(jù)庫(kù)了(這里是指關(guān)系型數(shù)據(jù)庫(kù),NoSQL 不在這討論)。第一節(jié)中我們使用了 Flask-SQLAlchemy 管理數(shù)據(jù)庫(kù),在 Flask-SQLAlchemy 中,數(shù)據(jù)庫(kù)使用 URL 指定,最流行的數(shù)據(jù)庫(kù) URL 格式如下:
數(shù)據(jù)庫(kù)引擎URL
MySQLmysql://username:password@hostname/database
Postgrespostgresql://username:password@hostname/database
SQLite(Unix)sqlite:////absolute/path/to/database
SQLite(Windows)sqlite:///c:/absolute/path/to/database
在 config.py 中我們已經(jīng)指定了數(shù)據(jù)庫(kù) URL,如果使用云平臺(tái)部署程序,直接將生成的數(shù)據(jù)庫(kù) URL 寫(xiě)到 config.py 中 SQLALCHEMY_DATABASE_URI 即可。
這里我們使用的是 SQLite 數(shù)據(jù)庫(kù)。Flask-SQLAlchemy 采用數(shù)據(jù)庫(kù)抽象層來(lái)操作數(shù)據(jù)庫(kù),也稱為對(duì)象關(guān)系映射(Object-Relational Mapper, ORM),在用戶不知不覺(jué)的情況下把高層的面向?qū)ο蟛僮鬓D(zhuǎn)換成低層的數(shù)據(jù)庫(kù)指令,因此易用性好。
我們已經(jīng)在 app/__init__.py 中實(shí)例化了 SQLAlchemy 類:
app/__init__.py
定義模型
模型類可以理解為數(shù)據(jù)庫(kù)中的一張表,F(xiàn)lask-SQLAlchemy 提供了一個(gè)基類和一系列輔助類和函數(shù)來(lái)讓我們定義模型的結(jié)構(gòu)。我們直接在 app 文件夾下創(chuàng)建一個(gè) models.py 文件。
鑒于每個(gè)網(wǎng)站需求都不一樣,所存的數(shù)據(jù)也不同,但本質(zhì)上是大同小異的。這里以筆者網(wǎng)站需求為例,需要?jiǎng)?chuàng)建 Developer,Integration 和 Channel 三個(gè)表。
app/models.py 部分代碼
上面的每個(gè) Class 都繼承了 Model 類,因此每個(gè)類在數(shù)據(jù)庫(kù)中都體現(xiàn)為一張表,表名用 __tablename__ 表示,一般用復(fù)數(shù)形式。
這里主要講一下一對(duì)多的關(guān)系。可以看到上面 Developer 和 Integration 及 Channel 都有一個(gè)一對(duì)多的關(guān)系,一個(gè)用戶可以有多個(gè)集成及多個(gè)頻道。 看到這兩句:
第一句表明添加到 Developer 表的 integrations 屬性表示這個(gè)關(guān)系的面向?qū)ο笠暯?,?duì)于一個(gè) Developer 實(shí)例,integrations 屬性將返回與 Developer 相關(guān)的所有 Integration,db.relationship() 第一個(gè)參數(shù)表明關(guān)系的另一端是哪個(gè)模型,backref 參數(shù)向 Integration 添加一個(gè) developer 屬性,從而定義反向關(guān)系。
第二句是在 Integration 表中創(chuàng)建一個(gè) developer_id 字段,這個(gè)字段被定義為外鍵,就是這個(gè)外鍵建立起了關(guān)系。傳給 db.ForeignKey() 的參數(shù) 'developers.id' 表明這列的值是 developers 表中行的 id 值。另外,__repr__() 方法返回一個(gè)具有可讀性的字符串表示模型,可以在調(diào)試和測(cè)試時(shí)使用。
下面我們就在命令行中操作一下數(shù)據(jù)庫(kù)。
首先執(zhí)行:
//創(chuàng)建 migrations 文件夾及相關(guān)文件
python manage.py db init
然后執(zhí)行 :
//自動(dòng)創(chuàng)建遷移腳本
python manage.py db migrate
//創(chuàng)建數(shù)據(jù)表或者升級(jí)到最新版本
python manage.py db upgrade
以后模型類有改動(dòng),比如刪除或添加列,都要執(zhí)行這兩個(gè)命令,更新數(shù)據(jù)庫(kù)表?,F(xiàn)在在項(xiàng)目目錄下應(yīng)該自動(dòng)生成了名為 dev 的數(shù)據(jù)庫(kù)。
接下來(lái)執(zhí)行如下命令進(jìn)入 Python Shell:
python manage.py shell
創(chuàng)建表
使用 db.create_all() 就可以根據(jù)模型類創(chuàng)建表。如圖:
使用 db.drop_all() 方法就可以刪除所有的表,但是這種方式比較粗暴,所有的數(shù)據(jù)也一同銷毀了。
插入行
以下命令在數(shù)據(jù)庫(kù)表中插入了一條數(shù)據(jù):
通過(guò)數(shù)據(jù)庫(kù)會(huì)話 db.session 來(lái)管理對(duì)數(shù)據(jù)庫(kù)所做的改動(dòng),在準(zhǔn)備把對(duì)象寫(xiě)入數(shù)據(jù)庫(kù)之前,首先要添加到會(huì)話中,然后用 commit() 方法提交會(huì)話。接下來(lái)我們繼續(xù)插入一條 Integration 數(shù)據(jù):
注意上面的 developer 屬性,正是我們?cè)?models.py 中 Developer 模型中定義的一對(duì)多關(guān)系 integrations 屬性的 backref 值, 所謂的反向關(guān)系即指在 Integration 表中每條數(shù)據(jù)都有一個(gè) developer 屬性指向 Developer 表中的某條數(shù)據(jù),這是一對(duì)多關(guān)系的高級(jí)表示。
現(xiàn)在可以用 developer.integrations 來(lái)查看該 developer 擁有的哪些集成,運(yùn)行截圖如下:
修改行
在提交數(shù)據(jù)庫(kù)會(huì)話之前,改變對(duì)象的某個(gè)屬性然后再提交即可更新行數(shù)據(jù)。如:
運(yùn)行截圖:
刪除行
調(diào)用 db.session.delete() 方法即可刪除行:
>>>db.session.delete(developer)>>>db.session.commit()
查詢行
Flask-SQLAlchemy 為每個(gè)模型提供了 query 對(duì)象,最基本的查詢是返回表中的所有記錄:
>>>Developer.query.all()
使用過(guò)濾器可以進(jìn)行更精確的查詢:
如果你退出了 shell 會(huì)話,前面創(chuàng)建的對(duì)象就不會(huì)以 Python 對(duì)象的形式存在,而是作為各自數(shù)據(jù)庫(kù)表中的行。這時(shí)需要重?cái)?shù)據(jù)庫(kù)中讀取行,再重新創(chuàng)建 Python 對(duì)象,如:
注意上面的 first() 方法,如果不加上,將返回一個(gè) BaseQuery 對(duì)象,這樣就不能直接用 new_developer 來(lái)訪問(wèn)它的屬性值。
在視圖函數(shù)中操作數(shù)據(jù)庫(kù)
上面介紹的所有數(shù)據(jù)庫(kù)操作可以直接在視圖函數(shù)中進(jìn)行。假設(shè)我們要做一個(gè)簡(jiǎn)陋的注冊(cè)功能,下面我們就來(lái)看看如何從網(wǎng)頁(yè)中獲取數(shù)據(jù)并保存在數(shù)據(jù)庫(kù)中。我們先定義一個(gè)用戶模型:
app/models.py
然后在 main 文件夾下創(chuàng)建一個(gè) forms.py 文件。
app/main/forms.py
我們使用了 flask-wtf 擴(kuò)展(pip install flask-wtf)來(lái)處理表單。
然后我們用在 index 頁(yè)面中顯示這個(gè)表單。
index.html
現(xiàn)在回到 views.py 中,在我們的視圖函數(shù)中作如下改動(dòng):
app/main/views.py
接下來(lái)我們運(yùn)行一下這個(gè)小試驗(yàn):
python manage.py runserver
總結(jié)
本文主要介紹了在 Flask 中是如何使用 Flask-SQLAlchemy 、Flask-Migrate來(lái)管理數(shù)據(jù)庫(kù),并且示范了數(shù)據(jù)從網(wǎng)頁(yè)儲(chǔ)存到數(shù)據(jù)庫(kù)的過(guò)程,這只是最基礎(chǔ)的部分,下次將探索如何在網(wǎng)頁(yè)上發(fā)送請(qǐng)求并且得到數(shù)據(jù),以及如何在頁(yè)面之間傳遞數(shù)據(jù)。
覺(jué)得本文有幫助?請(qǐng)分享給更多人
關(guān)注「猿助猿」成就頂級(jí)開(kāi)發(fā)
技術(shù)交流QQ群:517877452