摘要:關系關系數據庫通過使用關系在不同的表中建立連接。以下部分將介紹最常見的數據庫操作。如果數據庫已存在函數不會重新創建或更新數據庫表。到目前為止對象只存于中,他們還沒有被寫入數據庫。數據庫會話也叫事務。刪除行數據庫會話同樣有方法。
7、關系
關系數據庫通過使用關系在不同的表中建立連接。圖像5-1的關系圖表達了用戶和用戶角色之間的簡單關系。這個角色和用戶是一對多關系,因為一個角色可以從屬于多個用戶,而一個用戶只能擁有一個角色。
示例5-3的模型類展示了圖像5-1中表達的一對多關系。
示例5-3. hello.py:關系
class Role(db.Model): # ... users = db.relationship("User", backref="role") class User(db.Model): # ... role_id = db.Column(db.Integer, db.ForeignKey("roles.id"))
就像圖像5-1中看到的那樣,關系通過使用外鍵來連接兩行。添加給User模型的role_id列被定義為外鍵,且建立關系。db.ForeignKey()的參數roles.id指定的列應該理解為在roles表的行中持有id值的列。
添加到Role模型的users屬性表現了關系的面向對象的觀點。給定Role類的實例,users屬性會返回一組連接到該角色的用戶。指定給db.relationship()的第一個參數表明模型中關系的另一邊。如果類還未定義,這個模型可以作為字符串提供。
注意:之前在segmentdefault中遇到的問題,后來粗略閱讀了SQLAlchemy的源碼。ForeignKey類的column接收三種類型的參數,一種是“模型名.屬性名”;一種是“表名.列名”,最后一種沒看明白,下次試著用一下。
db.relationship()的backref參數通過給User模型增加role屬性來定義反向關系。這個屬性可以替代role_id訪問Role模型,是作為對象而不是外鍵。
大多數情況下db.relationship()可以定位自己的外鍵關系,但是有時候不能確定哪個列被用作外鍵。例如,如果User模型有兩個或更多列被定義為Role的外鍵,SQLAlchemy將不知道使用兩個中的哪一個。每當外鍵配置模棱兩可的時候,就必須使用額外參數db.relationship()。表格5-4列出一些常用配置選項用于定義關系。
表格5-4. 常用SQLAlchemy關系選項
建議:如果你有克隆在GitHub上的應用程序,你現在可以運行git checkout 5a來切換到這個版本的應用程序。
除了一對多關系還有其他種類關系。一對一關系可以表述為前面描述的一對多關系,只要將db.relationship()中的uselist選項設置為False,“多”就變為“一”了。多對一關系也可表示為將表反轉后的一對多關系,或表示為外鍵和db.relationship()定義在“多”那邊。最復雜的關系類型,多對多,需要一個被稱作關聯表的額外表。你將在第十二章學習多對多關系。
8、數據庫操作根據圖像5-1的數據庫圖,模型已經完全配置完且準備好使用。學習怎樣使用模型的最好方式就是使用Python shell。以下部分將介紹最常見的數據庫操作。
8.1、創建表首先要做的第一件事情就是指示Flask-SQLAlchemy基于模型類創建數據庫。db.create_all()函數會完成這些:
(venv) $ python hello.py shell >>> from hello import db >>> db.create_all()
如果你檢查應用程序目錄,你會發現名為data.sqlite的新文件,SQLite數據庫名在配置中給出。如果數據庫已存在db.create_all()函數不會重新創建或更新數據庫表。這會非常的不方便當模型被修改且更改需要應用到現有的數據庫時。更新現有的數據庫表的蠻力解決方案是先刪除舊的表:
>>> db.drop_all() >>> db.create_all()
不幸的是,這種方法有個不受歡迎的副作用就是摧毀舊的數據庫中的所有數據。更新數據庫問題的解決方案會在這章快結束的時候介紹。
8.2、插入行下面的示例會創建新的角色和用戶:
>>> 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 >>> print(user_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)
或,更簡潔的:
>>> db.session.add_all([admin_role, mod_role, user_role, ... user_john, user_susan, user_david])
為了寫對象到數據庫,需要通過它的commit()方法來提交會話:
>>> db.session.commit()
再次檢查id屬性;這個時候它們都已經被設置好了:
>>> print(admin_role.id) 1 >>> print(mod_role.id) 2 >>> print(user_role.id) 3
注:db.session數據庫會話和第四章討論的Flask會話沒有任何聯系。數據庫會話也叫事務。
數據庫會話在數據庫一致性上是非常有用的。提交操作會原子性地將所有添加到會話中的對象寫入數據庫。如果在寫入的過程發生錯誤,會將整個會話丟棄。如果你總是在一個會話提交相關修改,你必須保證避免因部分更新導致的數據庫不一致的情況。
8.3、修改行注:數據庫會話也可以回滾。如果調用db.session.rollback(),任何添加到數據庫會話中的對象都會恢復到它們曾經在數據庫中的狀態。
數據庫會話中的add()方法同樣可以用于更新模型。繼續在同一shell會話中,下面的示例重命名“Admin”角色為“Administrator”:
>>> admin_role.name = "Administrator" >>> db.session.add(admin_role) >>> db.session.commit()
8.4、刪除行注意:不過貌似我們在做更新操作的時候都不使用db.session.add(),而是直接使用db.session.commit()來提交事務。
數據庫會話同樣有delete()方法。下面的示例從數據庫中刪除“Moderator”角色:
>>> db.session.delete(mod_role) >>> db.session.commit()
注意刪除,和插入更新一樣,都是在數據庫會話提交后執行。
8.5、返回行Flask-SQLAlchemy為每個模型類創建一個query對象。最基本的查詢模型是返回對應的表的全部內容:
>>> Role.query.all() [, ] >>> User.query.all() [ , , ]
使用過濾器可以配置查詢對象去執行更具體的數據庫搜索。下面的例子查找所有被分配“User”角色的用戶:
>>> User.query.filter_by(role=user_role).all() [, ]
對于給定的查詢還可以檢查SQLAlchemy生成的原生SQL查詢,并將查詢對象轉換為一個字符串:
>>> 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。多個過濾器可以依次調用直到需要的查詢配置結束為止。
表格5-5展示一些查詢中常用的過濾器。完整的列表參閱SQLAlchemy文檔。
表格5-5.常用SQLAlchemy查詢過濾器
在需要的過濾器已經全部運用于query后,調用all()會觸發query執行并返回一組結果,但是除了all()以外還有其他方式可以觸發執行。表格5-6.展示其他查詢執行方法。
表格5-6.常用SQLAlchemy查詢執行器
關系的原理類似于查詢。下面的示例從兩邊查詢角色和用戶之間的一對多關系:
>>> users = user_role.users >>> users [, ] >>> users[0].role
此處的user_role.users查詢有點小問題。當user_role.users表達式在內部調用all()時通過隱式查詢執行來返回用戶的列表。因為查詢對象是隱藏的,是不可能通過附加查詢過濾器進一步提取出來。在這個特定的例子中,它可能是用于按字母排列順序返回用戶列表。在示例5-4中,被lazy = "dynamic"參數修改過的關系配置的查詢是不會自動執行的。
示例5-4. app/models.py:動態關系
class Role(db.Model): # ... users = db.relationship("User", backref="role", lazy="dynamic") # ...
用這種方式配置關系,user_roles.user查詢還沒有執行,所以可以給它增加過濾器:
>>> user_role.users.order_by(User.username).all() [, ] >>> user_role.users.count() 2
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37470.html
摘要:每個表單域都可以連接到一個或多個是一個用于檢查用戶提交的輸入是否合法的函數。表單域構造函數的第一個參數是一個,在渲染表單到時會使用。驗證確保提交的表單域不為空。表單域驗證都是直接從包中導入。表格展示了一組支持的標準表單域。 第二章中介紹的request對象公開了所有客戶端發送的請求信息。特別是request.form可以訪問POST請求提交的表單數據。 盡管Flask的request...
摘要:他和妻子四個孩子兩只狗和一只貓共同生活在俄勒岡州波特蘭市。。還邀請他根據書的內容,制作了兩個視頻教程。 showImg(http://img4.douban.com/lpic/s27205547.jpg); 這本書算是學習Flask的權威材料了,網上很多人都是推薦從這本書開始學習。起初,作者在自己的博客發布了一個大型的Flask建站教程,在這個教程大受歡迎的基礎上,才與OReilly公...
摘要:注對于開發者來說,傳給應用程序構造函數的參數是比較容易弄混淆的。在應程序中定義路由的最便捷的方式是通過顯示定義在應用程序實例之上的裝飾器,注冊被裝飾的函數來作為一個路由。一個常見的模式是使用裝飾器來注冊函數作為一個事件處理程序。 在這一章,你將學習Flask應用程序不同部分。同時你將編寫和運行你的第一個Flask web應用程序。 1、初始化 在這章,你將學到Flask應用程序的不...
摘要:有兩類應用級和請求級。一個響應中非常重要的部分是狀態碼,默認設置來指示請求已經成功處理。重定向通常由響應狀態碼注明并且重定向的由頭部的給出。因為這些變化,應用程序獲得一組基本的命令行選項。運行顯示可用信息在應用程序上下文的內部運行一個。 5、請求-響應循環 現在你已經玩過一個基本的Flask應用程序,你也許想要知道更多關于Flask如何施展魔力。下面章節描述了一些框架設計方面的特點。...
摘要:單元測試這個應用非常小以至于不需要太多的測試,但是作為示例會在示例中展示兩個簡單的測試定義。示例單元測試編寫好的測試使用的是來自于標準庫中標準的包。為了運行單元測試,可以在腳本中增加一個自定義的命令。 4、啟動腳本 頂層目錄中的manage.py文件用于啟動應用。這個腳本會在示例7-8中展示。 示例7-8. manage.py:啟動腳本 #!/usr/bin/env python im...
閱讀 2508·2023-04-25 17:37
閱讀 1189·2021-11-24 10:29
閱讀 3696·2021-09-09 11:57
閱讀 692·2021-08-10 09:41
閱讀 2243·2019-08-30 15:55
閱讀 2811·2019-08-30 15:54
閱讀 1942·2019-08-30 15:53
閱讀 895·2019-08-30 15:43