使用Flask-SQLAlchemy管理數據庫
擴展Flask-SQLAlchemy集成了SQLAlchemy,它簡化了連接數據庫服務器、管理數據庫操作會話等各種工作,讓Flask中的數據處理體驗變得更輕松。首先使用pipenv安裝Flask-SQLAlchemy以及其依賴(主要是SQLAlchemy):
pipenv install flask-sqlalchemy
下面在示例程序中實例化Flask-SQL-Alchemy提供的SQLAlchemy類,傳入程序實例app,以完成擴展的初始化:
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) db = SQLAlchemy(app)
為了便於使用,我們把實例化的擴展類對象命名為db。這個db對象代表我們的數據庫,它可以使用Flask-SQLAlchemy提供的所有功能。
雖然我們要使用的大部分類和函數都有SQLAlchemy提供,但在Flask-SQLAlchemy中,大多數情況下,我們不需要手動從SQLAlchemy導入類或函數。在sqlalchemy和sqlalchemy.orm模塊中實現的類和函數,以及其他幾個常用的模塊和對象都可以作為db對象的屬性調用。當我們創建這樣的調用時,Flask-SQLAlchemy會自動把這些調用轉發到對應的類、函數或模塊。
sqlite3數據庫安裝及客戶端軟件
sqlite下載地址:https://www.sqlite.org/download.html
下載sqlite-tools-win32-*.zip 和 sqlite-dll-win64-*.zip 壓縮文件
解壓后,創建文件夾 C:\sqlite3,在此文件夾下解壓上面兩個壓縮文件,將得到 sqlite3.def、sqlite3.dll 和 sqlite3.exe 文件。
添加 C:\sqlite3到PATH環境變量,在命令提示符下,使用sqlite3命令,將顯示如下
客戶端軟件官網:
https://www.softpedia.com/get/Internet/Servers/Database-Utils/SQLiteSpy.shtml
下載SQLiteSpy:
下載后:
打開sqlite的db文件:
連接數據庫服務器
DBMS通常會提供數據庫服務器運行在操作系統中。要連接數據庫服務器,首先要為我們的程序指定數據庫URL(Uniform Resource Identifier,統一資源標識符)。數據庫URI是一串包含各種屬性的字符串,其中包含了各種用於連接數據庫的信息。
URI代表統一資源標識符,是用來標識資源的一組字符串。URL是它的子集。
下面是一些常用的DBMS以及其數據庫URI格式實例。
在Flask-SQLAlchemy中,數據庫的URI通過配置變量SQLALCHEMY_DATABASE_URI設置,默認為SQLite內存型數據庫(sqlite: ///: memory: )。SQLite是基於文件的DBMS,不需要設置數據庫服務器,只需要指定數據庫文件的絕對路徑。我們使用app.root_path來定位數據庫文件的路徑,並將數據庫文件命名為data.db,如下所示
app.py:配置數據庫URI
import os app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///' + os.path.join(app.root_path, 'data.db'))
在生產環境下更換到其他類型的DBMS時,數據庫URL會包含敏感信息,所以這里優先從環境變量DATABASE_URL獲取(注意這里為了便於理解使用的是URL,不是URI)
SQLite數據庫文件名不限定后綴,常用的命名方式有foo.sqlite, foo.db,或是注明SQLite版本的foo.sqlite3。
設置好數據庫URI后,在python shell中導入並查看db對象會獲得下面的輸出:
>>> from app import db C:\Users\Lenovo\.virtualenvs\Lenovo-ezd1lI9Y\lib\site-packages\flask_sqlalchemy\__init__.py:774: UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:". 'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. ' C:\Users\Lenovo\.virtualenvs\Lenovo-ezd1lI9Y\lib\site-packages\flask_sqlalchemy\__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning. 'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and ' >>> db <SQLAlchemy engine=sqlite:///D:\flask\FLASK_PRACTICE\DataBase\data.db>
安裝並初始化Flask-SQLAlchemy后,啟動程序時會看到命令行下有警告,這是因為Flask-SQLAchemy建議你設置SQLALCHEMY_TRACK_MODIFICATIONS配置變量,這個配置變量決定是否追蹤對象的修改,這用於Flask-SQLALchemy的事件通知系統。這個配置的默認值為None,如果沒有特殊需要,可以設為False來關閉警告:
app.config['SQLALCHEMY_TRACE_MODIFICATIONS'] = False
再次導入db:
>>> from app import db >>> db <SQLAlchemy engine=sqlite:///D:\flask\FLASK_PRACTICE\DataBase\data.db> >>>
定義數據庫模型
用來映射到數據庫表的python類通常被稱為數據庫模型(model),一個數據庫模型類對應數據庫中的一個表。定義模型即使用python類定義表模式,並聲明映射關系。所有的模型都需要繼承Flask-SQLAlchemy提供的db.Model基類。后續的例子是一個筆記程序,筆記保存到數據庫中,你可以通過程序查詢、添加、更新和刪除筆記。
定義一個Note模型類,用來存儲筆記。
app.py: 定義Note模型
class Note(db.Model): id = db.Column(db.Integer, primary_key=True) body = db.Column(db.Text)
在這個模型類中,表的字段(列)由db.Column類的實例表示,字段的類型通過Column類構造方法的第一個參數傳入。在這個模型中,我們創建了一個類型為db.Integer的id字段和類型為db.Text的body列,分別存儲整型和文本。常用的SQLAlchemy字段類型如下表:
字段類型一般直接聲明即可,如果需要傳入參數,也可以添加括號。對於類似String的字符串列,有些使句酷會要求限定長度,因此最好為其制定長度。雖然使用Text類型可以存儲相對靈活的變長文本,但從性能上考慮,我們僅在必須的情況下使用Text類型,比如用戶發表的文章和評論等不限長度的內容。
一般情況下,字段的長度是由程序設計者自定的。盡管如此,也有一些既定的約束標准,比如姓名(英文)的長度一般不超過70個字符,中文名一般不超過20個字符,電子郵件地址的長度不超過254個字符,雖然個主流瀏覽器支持長達2048個字符的URL,但在網站中用戶資料設置的限度一般為255。對於超過一定長度的Email和URL,比如20個字符,會在顯示時添加省略號的形式。顯示的用戶名(username)允許重復,通常要短一些,以不超過36個字符為佳。在程序中可以根據需要來設定。
當在數據庫模型類中限制了字段的長度后,在接收對應數據的表單類字段里,也需要使用Length驗證器來驗證用戶的輸入數據。
默認情況下,Flask-SQLAlchemy會根據模型類的名稱生成一個表名稱,生成規則如下:
Message -> message # 單個單詞轉換為小寫
FooBar -> foo_bar # 多個單詞轉換為小寫並使用下划線分隔
Note類對應的表名即為note。如果想自己指定表名稱,可以通過定義__tablename__屬性來實現。字段名默認為類屬性名,也可以通過字段類構造方法的第一個參數指定(如Column('data', String(50))),或使用關鍵字name。根據我們定義的Note模型類,最終將生成一個Note表,表中包含id和body字段。
除了name參數,實例化字段類時常用的字段參數如下表:
不需要在所有列都建立索引。一般來說,取值可能性多(比如姓名)的列,以及經常被用來作為排序的參數(如時間戳)更適合建立索引。
在實例化字段類時,通過把參數primary_key設為True可以將其定義為主鍵。在我們定義的Nore類中,id字段即表的主鍵(primary key)。主鍵是每一條記錄(行)獨一無二的標識,也是模型類中必須定義的字段,一般命名為id或pk。
創建數據庫和表
如果把數據庫(文件)看作一個倉庫,為了方便取用,我們需要把貨物按照類型分別放置在不同的貨架上,這些貨架就是數據庫中的表。創建模型類后,我們需要手動創建數據庫和對應的表,就是建庫和建表。這通過對我們的db對象調用create_all()方法實現:
(Lenovo-ezd1lI9Y) D:\flask\FLASK_PRACTICE\DataBase>flask shell App: app [production] Instance: D:\flask\FLASK_PRACTICE\DataBase\instance >>> from app import db >>> from app import Note >>> db.create_all()
如果將模型類定義在單獨的模塊中,那么必須再調用db.create_all()方法前導入相應模塊,以便讓SQLAlchemy獲取模型類總定義的表信息,進而正確生成數據表。
通過下面的方式可以查看模型對應的SQL模式(建表語句):
>>> from app import db >>> from app import Note >>> db.create_all() >>> print CreateTable(Note.__table__) CREATE TABLE note ( id INTEGER NOT NULL, body TEXT, PRIMARY KEY (id) )
數據庫和表一旦創建后,之后對模型的改動不會自動作用的實際的表中。比如在模型類中添加或刪除字段,修改字段的名稱和類型,這時再次調用create_all()也不會更新表結構。如果要使改動生效,最簡單的方式是調用db.drop_all()方法刪除數據庫和表,然后再調用db.create_all()方法創建。
我們也可以自己實現一個自頂一個flask命令完成這個工作,例如:
app.py:用於創建數據庫和表的flask命令
import click @app.cli.command() def initdb(): db.create_all() click.echo('Initialized database.')
在命令行輸入flask initdb即可創建數據庫和表:
(Lenovo-ezd1lI9Y) D:\flask\FLASK_PRACTICE\DataBase>flask initdb
Initialized database.
在開發程序或是部署后,我們經常需要在python shell中手動操作數據庫(生產環境需注意備份),對於一次性操作,直接處理即可。對於需要重用的操作,我們可以編成flask命令、函數或是模型類的類方法。