SQLAlchemy 使用


1 定義模型

在 ORM 中,模型一般是一個 Python 類, 代表數據庫中的一張表, 類中的屬性對應數據庫表中的列。Flask-SQLAlchemy 創建的數據庫實例為模型提供了一個基類db.Model以及一系列輔助類和輔助函數,可用於定義 模型/表 的結構。下面的例子定義了兩個表,一個是用戶角色,一個是用戶信息

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

db.Column 類構造函數的第一個參數是數據庫表列/模型屬性 的類型

db.Column 中其余的參數指定屬性的配置選項

選項名 說 明
primary_key 如果設為 True,這列就是表的主鍵
unique 如果設為 True,這列不允許出現重復的值
index 如果設為 True,為這列創建索引,提升查詢效率
nullable 如果設為 True,這列允許使用空值;如果設為 False,這列不允許使用空值
default

為這列定義默認值

 

 

2 數據庫操作

2.1 創建表

SQLAlchemy 的實現,可以看到 Model 是一個元類,在繼承這個類來聲明子類的時候,會把表模型注冊到 sqlalchemy 里,所以在 create_all 之前必須把模型的聲明導入進來, 比如你可能需要這樣做from model.account import User,User的定義是def User(db.Model)這樣的,比如

      (venv) $ python hello.py shell  # 進入 Python shell >>> from hello import db # 從`hello.py`導入創建的數據庫實例 >>> db.create_all()

查看程序目錄,會發現新建了一個名為app.db的文件。這個 SQLite 數據庫文件 的名字就是在配置中指定的。如果數據庫表已經存在於數據庫中,那么 db.create_all() 不會重新創建或者更新這個表
更新現有數據庫表的粗暴方式是先刪除舊表再重新創建:
      >>> db.drop_all() >>> db.create_all()

這個方法有個我們不想看到的副作用,它把數據庫中原有的數據都銷毀了。末尾將會介紹一種稱數據庫遷移的方式用於更新數據庫

2.1 插入記錄

>>> from hello import Role, User >>> admin_role = Role(name='Admin') >>> mod_role = Role(name='Moderator') >>> user_role = Role(name='User') >>> user_john = User(username='john', role=admin_role) >>> user_susan = User(username='susan', role=user_role) >>> user_david = User(username='david', role=user_role)

模型的構造函數接受的參數是使用關鍵字參數指定的模型屬性初始值。注意,role 屬性也可使用,雖然它不是真正的數據庫列,但卻是一對多關系的高級表示。這些新建對象的 id 屬性並沒有明確設定,因為主鍵是由 Flask-SQLAlchemy 管理的。現在這些對象只存在於 Python 中,還未寫入數據庫。因此id 尚未賦值

通過數據庫會話管理對數據庫所做的改動,在 Flask-SQLAlchemy 中,會話由 db.session 表示。准備把對象寫入數據庫之前,先要將其添加到會話中

     >>> db.session.add(admin_role) >>> db.session.add(mod_role) >>> db.session.add(user_role) >>> db.session.add(user_john) >>> db.session.add(user_susan) >>> db.session.add(user_david)

或者簡寫成:
     >>> db.session.add_all([admin_role, mod_role, user_role, ... user_john, user_susan, user_david])

為了把對象寫入數據庫,我們要調用 commit() 方法提交會話:
>>> db.session.commit()

2.1 修改記錄

下面這個例子把 "Admin" 角色重命名為 "Administrator":

     >>> admin_role.name = 'Administrator' >>> db.session.add(admin_role) >>> db.session.commit()

2.1 刪除記錄

數據庫會話還有個 delete() 方法。下面這個例子把 "Moderator" 角色從數據庫中刪除

     >>> db.session.delete(mod_role) >>> db.session.commit()

2.1 查詢記錄

Flask-SQLAlchemy 為每個模型類都提供了 query 對象。最基本的模型查詢是取回對應表中的所有記錄:

>>> Role.query.all() [<Role u'Administrator'>, <Role u'User'>] >>> User.query.all() [<User u'john'>, <User u'susan'>, <User u'david'>]

使用過濾器可以配置 query 對象進行更精確的數據庫查詢。下面這個例子查找角色為 "User" 的所有用戶:
>>> User.query.filter_by(role=user_role).all() # user_role = Role(name='User'), role=user_role [<User u'susan'>, <User u'david'>]

若要查看 SQLAlchemy 為查詢生成的原生 SQL 查詢語句,只需把 query 對象轉換成字符串 :
>>> str(User.query.filter_by(role=user_role)) 'SELECT users.id AS users_id, users.username AS users_username, users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'

如果你退出了 shell 會話,前面這些例子中創建的對象就不會以 Python 對象的形式存在,而是作為各自數據庫表中的行。如果你打開了一個新的 shell 會話,就要從數據庫中讀取行, 再重新創建 Python 對象。下面這個例子發起了一個查詢,加載名為 "User" 的用戶角色:
>>> user_role = Role.query.filter_by(name='User').first()


可在 query 對象上調用的常用過濾器
過濾器 說明
filter() 把過濾器添加到原查詢上,返回一個新查詢
filter_by() 把等值過濾器添加到原查詢上,返回一個新查詢
limit() 使用指定的值限制原查詢返回的結果數量,返回一個新查詢
offset() 偏移原查詢返回的結果,返回一個新查詢
order_by() 根據指定條件對原查詢結果進行排序,返回一個新查詢
group_by() 根據指定條件對原查詢結果進行分組,返回一個新查詢

在查詢上應用指定的過濾器后,通過調用 all() 執行查詢,以列表的形式返回結果。除了 all() 之外,還有其他方法能觸發查詢執行

常用查詢執行函數

方法 說明
all() 以列表形式返回查詢的所有結果
first() 返回查詢的第一個結果,如果沒有結果,則返回 None
first_or_404() 返回查詢的第一個結果,如果沒有結果,則終止請求,返回 404 錯誤響應
get() 返回指定主鍵對應的行,如果沒有對應的行,則返回 None
get_or_404() 返回指定主鍵對應的行,如果沒找到指定的主鍵,則終止請求,返回 404 錯誤響應
count() 返回查詢結果的數量
paginate() 返回一個 Paginate 對象,它包含指定范圍內的結果
 

下面這個例子分別從關系的兩端查詢角色和用戶之間的一對 多關系:

     >>> users = user_role.users
     >>> users
     [<User u'susan'>, <User u'david'>] >>> users[0].role <Role u'User'>

這個例子中的 user_role.users 查詢有個小問題。執行 user_role.users 表達式時,隱含的查詢會調用 all() 返回一個用戶列表。query 對象是隱藏的,因此無法指定更精確的查詢 過濾器。就這個特定示例而言,返回一個按照字母順序排序的用戶列表可能更好。

在示例 5-4中,我們修改了關系的設置,加入了lazy = 'dynamic'參數,從而禁止自動執行查詢。

     class Role(db.Model): # ... users = db.relationship('User', backref='role', lazy='dynamic') # ...

這樣配置關系之后,user_role.users 會返回一個尚未執行的查詢,因此可以在其上添加過 濾器:

     >>> user_role.users.order_by(User.username).all()
     [<User u'david'>, <User u'susan'>] >>> user_role.users.count() 2



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM