前面的章節中我們已經學習了如何建立模型和關系,接下來我們學習如何使用模型的最好方法是在Python shell 中實際操作。並將介紹最常用的數據庫操作。
一.創建表
首先,我們要讓Flask-SQLAlchemy 根據模型類創建數據庫。方法是使用db.create_all()函數
(venv) $ python hello.py shell >>> from hello import db >>> db.create_all()
查詢mysql數據庫,我們會發現已經創建好的users和roles表,如果數據庫表已經存在於數據庫中,那么db.create_all()不會重新創建或者更新這個表。如果修改模型后要把改動應用到現有的數據庫中,這一特性會帶來不便。更新現有數據庫表的粗暴方式是先刪除舊表再重新創建。
>>> db.drop_all()
>>> db.create_all()
遺憾的是,這個方法有個我們不想看到的副作用,它把數據庫中原有的數據都銷毀了。
二.插入行
下面這段代碼創建了一些角色和用戶:
>>> 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 尚未賦值:
>>> print(admin_role.id) None >>> print(mod_role.id) None
通過數據庫會話管理對數據庫所做的改動,在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)
為了把對象寫入數據庫,我們要調用commit() 方法提交會話:
>>> db.session.commit()
然后去數據庫中查詢,就能查詢到插入的記錄了。
mysql> select * from roles; +----+---------------+ | id | name | +----+---------------+ | 1 | Administrator | | 2 | Mode | | 3 | User | +----+---------------+
數據庫會話能保證數據庫的一致性。提交操作使用原子方式把會話中的對象全部寫入數據庫。如果在寫入會話的過程中發生了錯誤,整個會話都會失效。如果你始終把相關改動放在會話中提交,就能避免因部分更新導致的數據庫不一致性。數據庫會話也可回滾。調用db.session.rollback() 后,添加到數據庫會話中的所有對象都會還原到它們在數據庫時的狀態。
三.修改行
在數據庫會話上調用add() 方法也能更新模型。我們繼續在之前的shell 會話中進行操作,下面這個例子把"Admin" 角色重命名為"Administrator":
>>> admin_role.name = 'Administrator' >>> db.session.add(admin_role) >>> db.session.commit()
四.刪除行
數據庫會話還有個delete() 方法。下面這個例子把"Moderator" 角色從數據庫中刪除:
>>> db.session.delete(mod_role)
>>> db.session.commit()
注意,刪除與插入和更新一樣,提交數據庫會話后才會執行。
五.查詢行
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 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()
filter_by() 等過濾器在query 對象上調用,返回一個更精確的query 對象。多個過濾器可以一起調用,直到獲得所需結果。下面列出了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 對象,它包含指定范圍內的結果 |