我的第一個python web開發框架(32)——介面代碼重構

来源:https://www.cnblogs.com/EmptyFS/archive/2018/08/20/9508636.html
-Advertisement-
Play Games

前面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/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • new delete初探 1,new有2個作用 開闢記憶體空間。 調用構造函數。 2,delete也有2個作用 釋放記憶體空間 調用析構函數。 如果用new開闢一個類的對象的數組,這個類里必須有預設(沒有參數的構造函數,或者有預設值的參數的構造函數)的構造函數。 釋放數組時,必須加[]。delete [ ...
  • 開始了,繼續說!字元串替換,就是預留著空間,後邊再定義要填上什麼,這種叫字元串格式化,其有兩種方法: % 和 format %s 就是一個占位符,這個占位符可以被其它的字元串代替 >>> "I like %s" % "python" 'I like python' string.format()的格 ...
  • 你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。 給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。 示例 1: 輸 ...
  • 目錄: 一、pickle模塊 二、課時31課後習題及答案 ****************** 一、pickle模塊 ****************** Python提供了一個標準模塊,使用這個模塊,就可以輕鬆地將列表、字典這類複雜類型存儲為文件了。這個模塊就是pickle模塊。 它幾乎可以把所有 ...
  • 序言 這個是從抖音上學來的,一開始刷抖音,遇到不少字元串跳舞的視頻,因此來實踐一下 主要分為三個部分 1. 靜態圖片轉靜態圖片 2. gif轉gif 3. 視頻轉視頻 靜態圖片轉靜態圖片 其實原理很簡單,讀取圖片的像素,新建一張大小一樣的圖片,根據原圖像素的灰度,決定是不是要顯示出來,併在新圖相應的 ...
  • 思路: 不要去考慮刪除的字眼,要考慮如何進行保存非 x 的值 這裡提供兩種解法,殊途同歸: 1.將其中非 x 的元素統計並保存 2.統計為 x 的元素個數,並將非 x 的元素保存 註意事項: 註意這裡代碼由於使用了引用(&),只能在 C++ 中編譯通過 使用指針的時候一定要註意開闢空間,否則之後可能 ...
  • 一、多態 定義:指允許不同子類的對象對父類同一消息能做出不同的響應。(重寫父類的方法) 即同一消息可以根據發送對象的不同而採用多種不同的行為方式。(發送消息就是函數調用) 1、面向對象的多態的實現前提: (1)要有繼承:類與類之間必須有繼承關係; (2)要有重寫:子類重寫父類的成員方法(可以不重寫, ...
  • *—*—python開發基礎(2)—*—*一、while迴圈1.while條件: 迴圈體 若條件滿足,迴圈體執行 若條件不滿足,迴圈體不執行 例:number = 1 #輸出結果:1 while number < 4: 2 print(number) 3 number = number + 12.死 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...