Pyslvs v0.9 大更新進度
- 改換 peewee 讀寫檔案格式
參考連結:
改換 peewee 讀寫檔案格式
後來發現 peewee 的操作還是比較「pythonic」 (笑)。
改寫學弟的範例,進行讀寫、複製三種操作:
import os from datetime import date from peewee import ( SqliteDatabase, Model, CharField, DateField ) fileName1 = "data.db" db1 = SqliteDatabase(fileName1) fileName2 = "data_copy.db" db2 = SqliteDatabase(fileName2) class BallBase(Model): name = CharField() date = DateField() speed = CharField() class Ball1(BallBase): class Meta: database = db1 class Ball2(BallBase): class Meta: database = db2 if __name__=='__main__': fileExist = os.path.isfile(fileName1) db1.connect() db1.create_tables([Ball1], safe=True) if not fileExist: print("create") steven = Ball1(name="steven", date=date(2017, 9, 30), speed="3m/s") steven.save() else: print("read and copy") db2.connect() db2.create_tables([Ball2], safe=True) with db2.atomic(): for ball in Ball1.select(): try: print(ball.name, ball.date, ball.speed) steven = Ball2(name=ball.name, date=ball.date, speed=ball.speed) steven.save() except: db2.rollback() db2.close() db1.close()
用繼承來改 connection 簡直方便多了。
上面的程式執行時,若第一個資料庫 data.db
不存在,會先建一個含有 steven
名稱的資料。
若已經存在,則會開啟第二個資料庫 data_copy.db
,將 data.db
的 Ball1 類型選取後填入 Ball2 的類型中,存入 data_copy.db
。
由於都繼承自 BallBase 類型,表單空位都相同。實際檢查,data.db
和 data_copy.db
的大小是一樣的。
with db2.atomic()
語句是建立一個 Transaction,類似 Qt Undo 功能的巨集,可以將多項改動儲存為一個檢查點,藉由 with 語句啟動 Transaction 紀錄,並在結束區塊時關閉它。使用 try 和 except 語句避免存入時發生錯誤,可用 rollback 方法退到上個檢查點。
注意在配合 with db2.atomic()
語句時,peewee 會自動開啟 Transaction、自動 commit 和自動在錯誤時啟動新的 Transaction,不用再使用 begin、commit 之類的 method;另外它也能寫成裝飾器 @db2.atomic()
來自動處理 function 中的內容,而由於類似巨集的功能,這個語句是可以巢狀使用的。
另一個顯式 (Explicit) 的用法是直接使用 with db.transaction()
語句:
with db.transaction() as txn: User.create(username='whiskers') # Roll back changes, which removes "whiskers". txn.rollback() # Create a new row for "mr. whiskers" which will be implicitly committed # at the end of the `with` block. User.create(username='mr. whiskers')
若怕中途出錯,可以開啟小的 Savepoints 來做紀錄:
with db.transaction() as txn: with db.savepoint() as sp1: User.create(username='mickey') with db.savepoint() as sp2: User.create(username='zaizee') sp2.rollback() # "zaizee" will not be saved, but "mickey" will be.
傳統的方法是關掉自動 commit 模式:
db.set_autocommit(False) db.begin() try: user.delete_instance(recursive=True) except: db.rollback() raise else: try: db.commit() except: db.rollback() raise finally: db.set_autocommit(True)
或是一開始就不使用:
db = SqliteDatabase(':memory:', autocommit=False) db.begin() User.create(username='somebody') db.commit()
以上就是 peewee 手冊 Transactions 章節的全部內容,比起 Qt 還滿好理解的。
當然 peewee 沒辦法靠 C++ 的 method 直接呈現為 QTableView 的欄位,不過將資料庫當作物件管理在開發上駕輕就熟,稍微寫下介面也不是什麼難事。
Comments
comments powered by Disqus