1. 程式人生 > >用 Flask 來寫個輕部落格 (5) — (M)VC_SQLAlchemy 的 CRUD 詳解

用 Flask 來寫個輕部落格 (5) — (M)VC_SQLAlchemy 的 CRUD 詳解

目錄

前文列表

擴充套件閱讀

SQLAlchemy 的 CRUD

CRUD 提供了在 Web 應用程式中所需要的所有操作和檢視資料的基礎功能, 尤其在 REST 風格的應用中, CRUD 就能實現一切所需功能.

本篇博文主要記錄 SQLAlchemy 實現 CRUD 的語句, 依然是在 manager shell 中完成:

(blog)fanguiju@fanguiju:/opt/JmilkFan-s-Blog$ python manage.py shell
>>> app
<Flask 'main'>
>>> User
<class 'models.User'> >>> db <SQLAlchemy engine='mysql+pymysql://root:[email protected]:3306/myblog?charset=utf8'>

為了讓在 manager shell 中的執行效果更直觀一些, 首先, 先對 User models 做一些修改:

from flask.ext.sqlalchemy import SQLAlchemy
from main import app


# INIT the sqlalchemy object
# Will be load the SQLALCHEMY_DATABASE_URL from config.py
db = SQLAlchemy(app) class User(db.Model): """Represents Proected users.""" # Set the name for table __tablename__ = 'users' id = db.Column(db.String(45), primary_key=True) username = db.Column(db.String(255)) password = db.Column(db.String(255)) def __init__(self, id, username, password)
:
self.id = id self.username = username self.password = password def __repr__(self): """Define the string format for instance of User.""" return "<Model User `{}`>".format(self.username)

Create 增添資料

為新建的 User models 新增一條記錄的操作看起來跟 Git 的提交操作非常類似, 其包含的意義也大致相同, 是為了儘量減少不必要的 I/O 操作:

  • add: 把資料新增到會話物件中 (資料狀態為待儲存)
  • commit: 將會話物件中的資料提交 (資料被寫入資料庫中)
>>> from uuid import uuid4
>>> user = User(id=str(uuid4()), username='jmilkfan', password='fanguiju')
>>> db.session.add(user)
>>> db.session.commit()

然後再檢視一下資料庫, 檢驗是否生效:

mysql> select * from users;
+--------------------------------------+----------+----------+
| id                                   | username | password |
+--------------------------------------+----------+----------+
| d2c3a206-c4d4-4ce9-91f1-ed4bbbb28c76 | jmilkfan | fanguiju |
+--------------------------------------+----------+----------+
1 row in set (0.00 sec)

從這個例子可以看出, 一個 class User 的例項化物件就是一條包含了欄位值的記錄物件, 將該記錄物件新增並提交到 session , 就會把記錄物件的資料寫入到資料庫中.

Retrieve 讀取資料

把資料新增僅資料庫表後, SQLAlchemy 可以通過 Model.query 方法對資料進行查詢. Model.query == db.session.query(Model) 兩種寫法是等效的. 區別在於前者使用的是 flask_sqlalchemy.BaseQuery object, 後者使用的是 sqlalchemy.orm.query.Query object . 但兩者本質上都是一個 Query 物件.

讀取資料有兩種情況:

  • 讀取一條資料: 需要指定唯一的過濾條件來獲取, 一般會使用主鍵作為過濾條件.
>>> user = User.query.first()
>>> user.username
u'fanguiju'
# 返回表中的第一條記錄
# 其中 User.query 返回的是 flask_sqlalchemy.BaseQuery object
# flask_sqlalchemy.BaseQuery object 擁有對資料庫操作的所有抽像方法

# or

>>> user = User.query.get('49f86ede-f1e5-410e-b564-27a97e12560c')
>>> user
<Model User `fanguiju`>
# 返回表中指定主鍵的一條記錄

# or

>>> user = db.session.query(User).filter_by(id='49f86ede-f1e5-410e-b564-27a97e12560c').first()
>>> user
<Model User `fanguiju`>
# 返回符合過濾條件的第一條記錄
# 其中 db.session.query(User).filter_by(id='49f86ede-f1e5-410e-b564-27a97e12560c') 返回的是一個 sqlalchemy.orm.query.Query object 物件
# sqlalchemy.orm.query.Query.first() 才是一個 User 物件
  • 讀取多條資料: 指定任意條件作為過濾條件或者不過濾的獲取全部資料
# 獲取多條記錄
>>> user = db.session.query(User).filter_by(username='fanguiju').all()
>>> user
[<Model User `fanguiju`>]
# 返回符合過濾條件的所有記錄, 將所有 username == fanguiju 的記錄都獲取

# 獲取全部資料
>>> users = User.query.all()
>>> users
[<Model User `fanguiju`>, <Model User `jmilkfan`>]
# or
>>> db.session.query(User).all()
[<Model User `fanguiju`>, <Model User `jmilkfan`>]

NOTE: 因為在 Flask 中的 SQLAlchemy 擁有 flask-sqlalchemy 和 sqlalchemy.orm 兩種語法, 為了避免看花眼的情況, 以後的程式碼中只會使用通用性更強一些的 sqlalchemy.orm 的語法.

除了上述兩種操作之外, 還有非常之多不同花樣的資料讀取方式, 讀取資料是 4 種操作型別中最複雜多樣的一中操作型別.

限制返回記錄的數目

這個返回特徵常與資料的分頁功能結合使用.

>>> users = db.session.query(User).limit(10).all()

返回記錄的排序

SQLAlchemy 預設會根據主鍵的順序來排序, 也是要顯示的使用 order_by 函式來指定排序條件和排序的方式:

# 正向排序
>>> users = db.session.query(User).order_by(User.username).all()
>>> users
[<Model User `fanguiju`>, <Model User `jmilkfan`>]

# 反向排序
>>> users = db.session.query(User).order_by(User.username.desc()).all()
>>> users
[<Model User `jmilkfan`>, <Model User `fanguiju`>]


>>> users = db.session.query(User).order_by(User.password).all()
>>> users
[<Model User `jmilkfan`>, <Model User `fanguiju`>]

查詢函式的鏈式呼叫

Query 物件提供了非常多且靈活的資料庫操作抽象方法, 我們可以鏈式的去組合這些方法來達到希望的效果. 但需要注意的是, 刪除操作的鏈式呼叫一定要謹慎而為.

>>> users = db.session.query(User).order_by(User.username).limit(10).all()

可以使用 dir() 內建函式來檢視一個 Query 物件提供的方法列表.

dir(db.session.query(User))

NOTE: 一條讀取語句的鏈式操作都是一個 first()all() 函式結束的. 它們會終止鏈式呼叫並返回結果.

Flask-SQLAlchemy 的專有分頁函式 pagination

pagination(): 是專門設計來實現分頁功能的函式, 所以必須由 flask_sqlalchemy.BaseQuery object 來呼叫.

>>> db.session.query(User).paginate(1,1)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Query' object has no attribute 'paginate'
  • 第一個引數表示查詢返回第幾頁的內容
  • 第二個引數表示每頁顯示的物件數量
>>> User.query.paginate(1,10)     # 查詢第 1 頁,且 1 頁顯示 10 條內容
<flask_sqlalchemy.Pagination object at 0x7f214419fe50>

paginate()first()/all() 不同, 後者返回的是一個 models 物件或 models 物件列表, 而前者返回的是一個 pagination 物件. 而且 pagination 物件還包含了幾個特有的屬性:

>>> user_page = User.query.paginate(1, 10)

# 獲取這一頁所包含的資料物件
>>> user_page.items
[<Model User `fanguiju`>, <Model User `jmilkfan`>]

# 獲取這一頁的頁碼
>>> user_page.page
1

# 獲取總共的頁數
>>> user_page.pages
1

# 是否有上一頁
>>> user_page.has_prev
False

# 如果有上一頁的話, 獲取上一頁的 pagination 物件
>>> if user_page.has_prev:
...     user_page.prev()
... 

# 是否有下一頁
>>> user_page.has_next
False

# 如果有下一頁的話, 獲取下一個的 pagination 物件
>>> if user_page.has_next:
...     user_page.next()
... 

Query 的過濾器

在查詢資料時, 可以根據一定的條件集合來獲得過濾後的資料. SQLAlchemy 提供了過濾器 query.filter_by()query.filter(), 過濾器接受的引數就是過濾條件, 有下面幾種形式:

  • 欄位鍵值對, EG. username='fanguiju'
  • 比較表示式, EG. User.id > 100
  • 邏輯函式, EG. in_/not_/or_

EXAMPLE:

>>> user = db.session.query(User).filter(User.username.in_(['fanguiju', 'jmilkfan'])).limit(1).all()   # 當然也可以結合鏈式函式來使用
>>> user
[<Model User `fanguiju`>]

>>> user = db.session.query(User).filter(not_(User.password == None)).all()
>>> user
[<Model User `fanguiju`>, <Model User `jmilkfan`>]

>>> user = db.session.query(User).filter(or_(not_(User.username == None), User.password != None)).all()
>>> user
[<Model User `fanguiju`>, <Model User `jmilkfan`>]

可以將 query.filter() 內建的邏輯函式 in_/not_/or_ 結合使用來實現更復雜的過濾.

Update 更新資料

>>> user = db.session.query(User).first()
>>> user.username
u'fanguiju'

>>> user = db.session.query(User).update({'username': 'update_fanguiju'})
>>> db.session.commit()

>>> user = db.session.query(User).first()
>>> user.username
u'update_fanguiju'

如上述例子, 先定位到你希望更新的記錄, 然後通過 Query 物件的 update() 傳遞要更新內容. 注意: 更新的內容必須是 Dict 資料型別.

需要注意的是: 就如使用原生 SQL 指令來更新記錄一樣, 如果沒有指定要更新具體的哪一條記錄的話, 會將該欄位所在列的所有記錄值一同更新, 所以切記使用過濾條件來定位到具體需要更新的記錄.

而且 update() 會自動的新增 User 的例項化物件到 session 中, 所以直接 commit 就可以寫入到資料庫了.

Delete 刪除資料

>>> user = db.session.query(User).first()
>>> user
<Model User `update_fanguiju`>

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

將查詢返回的 User 例項化物件進行 session 的 delete 操作, 就能夠刪除該物件所對映的記錄資料了.

相關推薦

Flask 部落 (5) — (M)VC_SQLAlchemyCRUD

目錄 前文列表 擴充套件閱讀 SQLAlchemy 的 CRUD CRUD 提供了在 Web 應用程式中所需要的所有操作和檢視資料的基礎功能, 尤其在 REST 風格的應用中, CRUD 就能實現一切所需功能. 本篇博文主要記

Flask 部落 (14) — M(V)C_實現專案首頁的模板

目錄 前文列表 實現所需要的檢視函式 在開始實現首頁模板之前, 我們為了除錯和顯示的方便, 首先偽造一些假資料: fake_data.py import rand

Flask 部落 (6) — (M)VC_models 的關係(one to many)

目錄 前文列表 擴充套件閱讀 前言 models 中的關係能夠對映成為關係型資料庫表中的關係,models 中可以相互建立引用,使得相關聯的資料能夠很容易的一次性的從資料庫中取出。 一對多 首先繼續在 models

Flask 部落 (13) — M(V)C_WTForms 服務端表單檢驗

目錄 前文列表 用 Flask 來寫個輕部落格 (1) — 建立專案 用 Flask 來寫個輕部落格 (2) — Hello World! 用 Flask 來寫個輕部落格 (3) — (M)VC_連線 MySQL 和 SQLAlchemy

Flask 部落 (3) — (M)VC_連線 MySQL 和 SQLAlchemy

目錄 前文列表 擴充套件閱讀 前言 大多數的應用程式在開發之前都需要先進行資料庫設計這一環節,所以本篇就先來記錄在 Flask 中如何使用 Models,也就是 MVC 模式中的 M 。 Models 模型 模型 就

Flask 部落 (7) — (M)VC_models 的關係(many to many)

目錄 目錄 前文列表 擴充套件閱讀 前期準備 多對多 使用樣例 前文列表 擴充套件閱讀 前期準備 在實現多對多之前,我們還需要先增加一個評論(Comment) models class,而且 Comment 是 P

Flask 部落 (26) — 使用 Flask-Celery-Helper 實現非同步任務

目錄 前文列表 擴充套件閱讀 Celery Celery 是使用 Python 多工庫來編寫的任務佇列工具, 可以 並行 的執行任務. 我們會將執行時間較長但又不那

Flask 部落 (16) — MV(C)_Flask Blueprint 藍圖

目錄 前文列表 擴充套件閱讀 Blueprint 藍圖 Blueprint 藍圖是一種用來擴充套件已有 Flask 應用結構的方法,通過藍圖的思想我們能夠把自己的 Application 拆分成為不同的元件。通常,一個元件代

Flask 部落 (23) — 應用 OAuth 實現 Facebook 第三方登入

目錄 前文列表 擴充套件閱讀 第三方登入流程 Resource Owner:資源所有者,本文中又稱”使用者”(user)。 Authorization server:認證伺服器,即服務提供商專門用來處理認證的伺服器。

Flask 部落 (17) — MV(C)_應用藍圖重構專案

目錄 前文列表 重構目錄結構 現在專案的目錄結構: (env) [[email protected] opt]# tree JmilkFan-s-Blog/

Flask 部落 (24) — 使用 Flask-Login 保護應用安全

目錄 前文列表 擴充套件閱讀 使用者登入帳號 Web上的使用者登入功能應該是最基本的功能了,但這個功能可能並沒有你所想像的那麼簡單,這是一個關係到使用者安全的功能. 在現代這樣速度的計算速度下,用窮舉法破解賬戶的密碼會是一件

Flask 部落 (2) — Hello World!

目錄 前文列表 擴充套件閱讀 實現最簡單的 Flask 應用 建立 config.py 檔案 該檔案是整個 Flask 應用程式的配置檔案,定義我們常用的配置類 Config/ProdConfig/DevConfig

Flask 部落 (31) — 使用 Flask-Admin 實現 FileSystem 管理

目錄 前文列表 擴充套件閱讀 編寫 FileSystem Admin 頁面 所謂的 FileSystem Admin 功能, 就是哪呢鋼構通過後臺管理頁面檢視並修改 blog 專案中, 或自定義的檔案目錄內容. 使用 F

Flask 部落 (37) — 在 Github 上為第一階段的版本打 Tag

目錄 目錄 前文列表 打 Tag 前文列表 第一階段結語 從 2016/11/13 至今 2017/01/02 剛好 50 天, <<用 Flask 來寫個輕部落格>> 系列博文的第一階段也就算告一段

Flask 部落 (32) — 使用 Flask-RESTful 構建 RESTful API 之一

目錄 前文列表 擴充套件閱讀 RESTful API REST(Representational State Transfer):是一種軟體架構的設計風格,而不是一種標準。主要用於 C/S 架構的軟體設計,也能很好的支援 B

本想python 好友發送給我指定的號,然後截屏發給好友,但是消息分割處理小毛病,還在測試

nbsp for wechat 全屏 名片 .text pict 參數 end from wxpy import * from PIL import ImageGrab import os img_path_name=‘1.jpg‘ def jiepin(img

在你的部落投放Google廣告步驟(推薦)

2、放程式碼:申請後會收到Google的信,確認成功後通過上述頁面進去,生成與自己網頁風格相配的程式碼,放到自己網頁適當位置即可。注意:放置程式碼要符合Google政策,比如每頁放置的程式碼個數等,不要違規。3、等待PIN:放完程式碼就等自己的收入了,達到50$後Google會給你寄信,是PIn碼,按信中的提

maven建立scala和java專案程式碼環境(圖文)(Intellij IDEA(Ultimate版本)、Intellij IDEA(Community版本)和Scala IDEA for Eclipse皆適用)(博主推薦)

  不多說,直接上乾貨! 為什麼要寫這篇部落格?   首先,對於spark專案,強烈建議搭建,用Intellij IDEA(Ultimate版本),如果你還有另所愛好嘗試Scala IDEA for Eclipse,有時間自己去玩玩。但最好追隨大流。   對於hadoop專案,強烈建議用

Scala IDEA for Eclipse裡maven建立scala和java專案程式碼環境(圖文

  這篇部落格   是在Scala IDEA for Eclipse裡手動建立scala程式碼編寫環境。   本博文,教大家,用maven來建立。   第一步:安裝scala外掛   因為,我win7下的scala環境是2.10.4    所以,選擇下載的

段子了 誰說部落不能段子

1. 你就是我的第一志願 因為我想上你 2.我願有一天能牽著你的手 ,去敬各位來賓的酒 3.我給你變個魔術,我變完了 我變得更喜歡你了,但你卻看不到。 4.我喜歡一個人,  那人一定很漂亮吧 !你太自戀了。 5.在遇見你之前我有兩顆心,,一顆善心 一顆噁心,,現在我只有一顆