前面ORM模塊我們已經完成了開發,接下來要做的就是對項目代碼進行重構了。因為對底層資料庫操作模塊(db_helper.py)進行了改造,之前項目的介面代碼全都跑不起來了。 在寫ORM模塊時,我們已經對產品介面的分頁查詢、新增、修改、獲取指定產品實體介面已經重構好了,還剩下刪除介面未完成 如果前面代碼 ...
前面ORM模塊我們已經完成了開發,接下來要做的就是對項目代碼進行重構了。因為對底層資料庫操作模塊(db_helper.py)進行了改造,之前項目的介面代碼全都跑不起來了。
在寫ORM模塊時,我們已經對產品介面的分頁查詢、新增、修改、獲取指定產品實體介面已經重構好了,還剩下刪除介面未完成
1 @delete('/api/product/<id:int>/') 2 def callback(id): 3 """ 4 刪除指定記錄 5 """ 6 # 編輯記錄 7 sql = """delete from product where id=%s returning id""" 8 vars = (id,) 9 # 寫入資料庫 10 result = db_helper.write(sql, vars) 11 # 判斷是否提交成功 12 if result: 13 return web_helper.return_msg(0, '成功') 14 else: 15 return web_helper.return_msg(-1, "刪除失敗")
如果前面代碼有認真學習的小伙伴看到這段代碼,要改成ORM方式應該很容易實現了
只需要將第7行到第10行替換對應的調用代碼就可以了
1 @delete('/api/product/<id:int>/') 2 def callback(id): 3 """ 4 刪除指定記錄 5 """ 6 # 實例化product表操作類ProductLogic 7 _product_logic = product_logic.ProductLogic() 8 result = _product_logic.delete_model(id) 9 # 判斷是否提交成功 10 if result: 11 return web_helper.return_msg(0, '成功') 12 else: 13 return web_helper.return_msg(-1, "刪除失敗")
首先是初始化產品邏輯層操作類,然後調用delete_model()這個方法就可以了
當你習慣這種寫法以後,你會發現實現各個介面會變得非常的簡單與方便,開發速度比之前也提升了很多
產品分類相關介面(product_class.py)與產品相關介面(product.py)功能差不多,具體實現我就不一一講解了,大家可以自己試試
產品分類的刪除分類介面大家會看到它的代碼與產品刪除介面差不多,不過多了一個該分類是否已經被引用的一個判斷,對於這個下麵專門說明一下
1 @delete('/api/product_class/<id:int>/') 2 def callback(id): 3 """ 4 刪除指定記錄 5 """ 6 # 判斷該分類是否已經被引用,是的話不能直接刪除 7 sql = """select count(*) as total from product where product_class_id=%s""" % (id,) 8 # 讀取記錄 9 result = db_helper.read(sql) 10 if result and result[0].get('total', -1) > 0: 11 return web_helper.return_msg(-1, "該分類已被引用,請清除對該分類的綁定後再來刪除") 12 13 # 編輯記錄 14 sql = """delete from product_class where id=%s returning id""" 15 vars = (id,) 16 # 寫入資料庫 17 result = db_helper.write(sql, vars) 18 # 判斷是否提交成功 19 if result: 20 return web_helper.return_msg(0, '成功') 21 else: 22 return web_helper.return_msg(-1, "刪除失敗")
這段代碼後半部分可以參考產品的刪除介面實現,前半部分需要調用產品方法進行判斷處理。
在編寫時我們會發現,我們的ORM並沒有直接判斷記錄是否存在的方法,只有一個用於獲取指定條件記錄數的方法。
一般來說,我們在開發時發現ORM沒有自己想要的方法時,我們需要做以下思考:
1.有沒有替代可以實現的方法存在
2.該功能是否是常用的功能,能否封裝成公共方法,如果可以就將它封裝到邏輯層基類(ORM模塊)中去,讓所有繼承的子類都擁有這個功能
3.如果它只是對指定表單操作時才用到,就將它封裝到該邏輯層子類,方便該子類要用到時可以隨時調用
這段代碼的要求是判斷指定的分類是否被產品引用,抽象出來的意思就是判斷指定條件的記錄是否存在,對於這個功能有開發經驗的小伙伴很容易判斷它是很多地方都有可能要用到的通用方法,所以我們需要在ORM中增加一下這個方法。而我們ORM已經存在get_count()這個獲取記錄數的方法存在了,我們可以通過調用這個方法來判斷記錄數量是否大於0,來得出指定條件的記錄是否存在這樣的結果。
def exists(self, wheres): """檢查指定條件的記錄是否存在""" return self.get_count(wheres) > 0
有了這個方法,我們就可以繼續對產品分類刪除介面進行改造了
1 @delete('/api/product_class/<id:int>/') 2 def callback(id): 3 """ 4 刪除指定記錄 5 """ 6 # 實例化product表操作類ProductLogic 7 _product_logic = product_logic.ProductLogic() 8 # 判斷該分類是否已經被引用,是的話不能直接刪除 9 if _product_logic.exists('product_class_id=' + str(id)): 10 return web_helper.return_msg(-1, "該分類已被引用,請清除對該分類的綁定後再來刪除") 11 12 # 實例化product_class表操作類product_class_logic 13 _product_class_logic = product_class_logic.ProductClassLogic() 14 result = _product_class_logic.delete_model(id) 15 # 判斷是否提交成功 16 if result: 17 return web_helper.return_msg(0, '成功') 18 else: 19 return web_helper.return_msg(-1, "刪除失敗")
通過這個例子,大家在實際開發過程中,可以靈活的根據自己需要,來增加或改造對應的底層方法,積累你自己的底層框架代碼,那麼隨著開發時間的增加,你開發起各種功能來就會越加得心應手了。
細心的朋友會發現,ORM模塊的緩存部分,多了一個get_model_for_cache_of_where()方法,下麵我來說明一下它的用途。
我們在開發時,除了通過主鍵id來獲取記錄實體以外,在有的數據表中,還會存在第二個主鍵,或多個主鍵的情況,我們需要通過這些主鍵來獲取對應的記錄實休,比如說管理員或用戶表中的登錄賬號欄位;訂單表中的訂單編碼欄位等。
正常情況下,我們直接通過get_model()方法就可以讀取對應的記錄了,如果我們想減少資料庫的查詢,直接在緩存中如何使用呢?直接存取記錄實體,由於這些額外的主鍵並沒有與ORM中的編輯與刪除操作關聯,即在進行編輯與刪除操作時不會同步更新用其他主鍵存儲的實體內容,這樣就會產生臟數據。所以我們可以換一種思路來實現,我們可以將這些額外的主鍵和對應的值生成緩存組合key,裡面存儲對應的記錄實體id,也就是說在存儲記錄實體時,還是使用原來的主鍵id存儲該實體,然後用額外主鍵和對應值生成緩存組合key中存儲主鍵id,在獲取記錄實體時,先用這個組合key提取對應的id,再用這個id來獲取記錄實體。這個說明好像有點繞,大家自己debug一下就很容易明白其中的原理了,下麵看代碼:
1 def get_model_for_cache_of_where(self, where): 2 """ 3 通過條件獲取記錄實體————條件必須是額外的主鍵,也就是說記錄是唯一的(我們經常需要使用key、編碼或指定條件來獲取記錄,這時可以通過當前方法來獲取) 4 :param where: 查詢條件 5 :return: 記錄實體 6 """ 7 # 生成實體緩存key 8 model_cache_key = self.__table_name + encrypt_helper.md5(where) 9 # 通過條件從緩存中獲取記錄id 10 pk = cache_helper.get(model_cache_key) 11 # 如果主鍵id存在,則直接從緩存中讀取記錄 12 if pk: 13 return self.get_model_for_cache(pk) 14 15 # 否則從資料庫中獲取 16 result = self.get_model(where) 17 if result: 18 # 存儲條件對應的主鍵id值到緩存中 19 cache_helper.set(model_cache_key, result.get(self.__pk_name)) 20 # 存儲記錄實體到緩存中 21 self.set_model_for_cache(result.get(self.__pk_name), result) 22 return result
下麵改造調用例子(請查看login.py第35行附近)
1 ############################################################## 2 ### 獲取登錄用戶記錄,併進行登錄驗證 ### 3 ############################################################## 4 sql = """select * from manager where login_name='%s'""" % (username,) 5 # 從資料庫中讀取用戶信息 6 manager_result = db_helper.read(sql) 7 # 判斷用戶記錄是否存在 8 if not manager_result: 9 return web_helper.return_msg(-1, '賬戶不存在')
我們可以改造為:
1 ############################################################## 2 ### 獲取登錄用戶記錄,併進行登錄驗證 ### 3 ############################################################## 4 _manager_logic = manager_logic.ManagerLogic() 5 # 從資料庫中讀取用戶信息 6 manager_result = _manager_logic.get_model_for_cache_of_where('login_name=' + string(username)) 7 # 判斷用戶記錄是否存在 8 if not manager_result: 9 return web_helper.return_msg(-1, '賬戶不存在')
還有登錄介面最底部,更新管理員最後登錄時、登錄ip和累加登錄次數需要改造,具體代碼如下:
1 ############################################################## 2 ### 更新用戶信息到資料庫 ### 3 ############################################################## 4 # 更新當前管理員最後登錄時間、Ip與登錄次數(欄位說明,請看數據字典) 5 sql = """update manager set last_login_time=%s, last_login_ip=%s, login_count=login_count+1 where id=%s""" 6 # 組合更新值 7 vars = ('now()', ip, manager_id,) 8 # 寫入資料庫 9 db_helper.write(sql, vars)
我們可以更改為:
1 ############################################################## 2 ### 更新用戶信息到資料庫 ### 3 ############################################################## 4 # 更新當前管理員最後登錄時間、Ip與登錄次數(欄位說明,請看數據字典) 5 fields = { 6 'last_login_time': 'now()', 7 'last_login_ip': string(ip), 8 'login_count': 'login_count+1', 9 } 10 # 寫入資料庫 11 _manager_logic.edit_model(manager_id, fields)
對於欄位值,如果為字元串、具體時間、json等類型的,也就是說需要用單撇號括起來的,我們就需要調用string_helper模塊的string方法進行轉換,它可以為變數增加單撇號,如果直接賦字元串值,生成的sql語句是沒有單撇號的,這裡要註意一下
如果是數值類型,直接寫值就可以了,當然直接賦字元串值也沒有關係,因為生成sql是不會自動添加單撇號的
如果要賦postgresql系統變數,如now(),直接像上面這樣寫就可以了
如果欄位是數值型,要讓它進行計算,直接像上面這樣寫也行,可以是多個欄位用加號連起來。當然你也可以將欄位時讀出來進行計算後再賦值提交也沒有問題
具體操作需要大家自己多debug,多測試使用才知道怎麼應用到真實項目中。
版權聲明:本文原創發表於 博客園,作者為 AllEmpty 本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。
python開發QQ群:669058475 作者博客:http://www.cnblogs.com/EmptyFS/