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