我的第一個python web開發框架(29)——定制ORM(五)


  接下來我們要封裝的是修改記錄模塊。

  先上產品信息編輯接口代碼

 1 @put('/api/product/<id:int>/')
 2 def callback(id):
 3     """
 4     修改記錄
 5     """
 6     name = web_helper.get_form('name', '產品名稱')
 7     code = web_helper.get_form('code', '產品編碼')
 8     product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '產品分類'))
 9     standard = web_helper.get_form('standard', '產品規格')
10     quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保質期')
11     place_of_origin = web_helper.get_form('place_of_origin', '產地')
12     front_cover_img = web_helper.get_form('front_cover_img', '封面圖片')
13     content = web_helper.get_form('content', '產品描述', is_check_special_char=False)
14     # 防sql注入攻擊處理
15     content = string_helper.filter_str(content, "'")
16     # 防xss攻擊處理
17     content = string_helper.clear_xss(content)
18     is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否啟用'))
19 
20     # 組成編輯Sql
21     sql = """
22           update product
23             set name=%s, code=%s, product_class_id=%s, standard=%s, quality_guarantee_period=%s,
24                 place_of_origin=%s, front_cover_img=%s, content=%s, is_enable=%s
25           where id=%s returning id"""
26     vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content, is_enable, id)
27     # 寫入數據庫
28     result = db_helper.write(sql, vars)
29     # 判斷是否提交成功
30     if result and result[0].get('id'):
31         return web_helper.return_msg(0, '成功')
32     else:
33         return web_helper.return_msg(-1, "提交失敗")

  第21行到25行,是我們常用修改記錄的sql語句,它與插入記錄差別比較大,但也有相似的地方,那就是都是字段與值一一對應,我們同樣可以使用字典的方式將它做為ORM的參數值,在ORM中進行轉換處理,組合成對應的sql語句。

  操作步驟:

  1.將新增記錄時的字段名與值,使用字典方式存儲起來

  2.將字典做為參數傳給ORM編輯記錄方法

  3.編輯記錄方法接收到參數以后,使用for循環,將字段名提取出來,生成sql編輯字段名、數組和字典替換數組,即:update table_name set 字段名=值,字段名=值... where 條件,這里需要將字典中的字段名提取出來組合成“字段名=值,字段名=值...”這樣的串

  這個步驟看起來跟新增記錄差不多,只是生成sql的結果不一樣而已。

 

  同樣的,我們看看產品記錄編輯的例子,方便進行理解

  例如:我們需要修改產品Id為2的記錄,將它的名稱和產品詳情進行更改,我們可以將更改內容組合成一個字典

fields = {
    'name': "'產品名稱'",
    'content': "'產品詳情'",
}

  然后可以通過for循環,將字典參數進行處理,提取出來存儲到list中

# 拼接字段與值
field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]

  我們同樣使用for循環,遍歷所有字典內容,將它們提取出來進行組合。可能有朋友對上面這個for語句不太理解,我將它分解一下

field_list = []
for key in fields.keys():
    field_list.append(key + ' = %(' + key + ')s')

  for循環是python中應用最多的語句之一,它通過可以將很復雜的需要很多代碼才能實現的語句,用一行語句將它實現出來,如果你能熟練掌握,你會發現它不但能簡化代碼,同時也提高了代碼的可讀性。

  執行完后,field_list的值為:

field_list = ['content = %(content)s', 'name = %(name)s']

  然后我們設置一個sql字符串拼接字典,將表名、字段名字符串與值字符串存儲進去,在存儲前使用join方式進行拼接,生成用逗號分隔的字符串

# 設置sql拼接字典
parameter = {
    'table_name': self.__table_name,
    'field_list': ','.join(field_list)
}

  執行后生成的值為:

parameter = {'field_list': 'content = %(content)s,name = %(name)s', 'table_name': 'product'}

  由於是編輯記錄,所以我們通常要指定編輯記錄的條件,比如編輯id=1的記錄,或者更新所有記錄,這時就不需要指定條件,所以我們還需要添加條件進來

# 如果存在更新條件,則將條件添加到sql拼接更換字典中
if wheres:
    parameter['wheres'] = ' where ' + wheres
else:
    parameter['wheres'] = ''

  執行后parameter值為:

parameter = {'wheres': ' where id=2', 'field_list': 'content = %(content)s,name = %(name)s', 'table_name': 'product'}

  在執行更新操作時,我們也經常會指定返回記錄的字段值回來使用。比如說:我們要更新id為2的記錄,將它設置為禁用狀態,然后需要同步更新該分類記錄的產品數量,正常來說我們需要執行修改操作以后,還需要將記錄查詢出來,然后獲取它的分類id,然后再去更新該分類的產品數量,而postgresql由於擁有returning,所以我們只需要將分類id放在returning語句中就可以了,執行更新操作后會將分類id同時返回回來給我們使用。

# 如果有指定返回參數,則添加
if returning:
    parameter['returning'] = ', ' + returning
else:
    parameter['returning'] = ''

  執行后parameter值為:

parameter = {'wheres': ' where id=2', 'field_list': 'content = %(content)s,name = %(name)s', 'table_name': 'product', 'returning': ', product_class_id'}

  然后將它們與編輯sql合成

sql = "update %(table_name)s set %(field_list)s %(wheres)s returning id %(returning)s" % parameter

  執行后sql值為:

'update product set content = %(content)s,name = %(name)s  where id=1 returning id , product_class_id'

  最后將它與最開始提交的字典參數進行合成

sql = sql % fields

  生成最終可執行的sql語句

"update product set content = '產品詳情',name = '產品名稱'  where id=2 returning id , product_class_id"

  完整代碼

 1     def edit(self, fields, wheres='', returning=''):
 2         """批量編輯數據庫記錄"""
 3         ### 拼接sql語句 ###
 4         # 拼接字段與值
 5         field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
 6         # 設置sql拼接字典
 7         parameter = {
 8             'table_name': self.__table_name,
 9             'field_list': ','.join(field_list)
10         }
11         # 如果存在更新條件,則將條件添加到sql拼接更換字典中
12         if wheres:
13             parameter['wheres'] = ' where ' + wheres
14         else:
15             parameter['wheres'] = ''
16 
17         # 如果有指定返回參數,則添加
18         if returning:
19             parameter['returning'] = ', ' + returning
20         else:
21             parameter['returning'] = ''
22 
23         # 生成sql語句
24         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning id %(returning)s" % parameter
25         sql = sql % fields
26 
27         return self.execute(sql)

   大家自己多debug一下,就很容易理解這個模塊是怎么生成sql的

 

  代碼出來了,我們直接上單元測試跑一下看看效果吧

#!/usr/bin/evn python
# coding=utf-8

import unittest
from common.string_helper import string
from logic import product_logic

class DbHelperTest(unittest.TestCase):
    """數據庫操作包測試類"""

    def setUp(self):
        """初始化測試環境"""
        print('------ini------')

    def tearDown(self):
        """清理測試環境"""
        print('------clear------')

    def test(self):
        ##############################################
        # 只需要看這里,其他代碼是測試用例的模板代碼 #
        ##############################################
        # 實例化product表操作類ProductLogic
        _product_logic = product_logic.ProductLogic()
        # 測試編輯記錄
        fields = {
            'name': "'產品名稱'",
            'content': "'產品詳情'",
        }
        result = _product_logic.edit(fields, 'id=2', 'product_class_id')
        print(result)

        ##############################################

if __name__ == '__main__':
    unittest.main()

  輸出結果:

------ini------
[{'id': 2, 'product_class_id': 1}]
------clear------

 

  對於通過主鍵id修改記錄的操作,我們也是最常用的,所以我們可以增加一個通過主鍵值來修改記錄的方法,可以在寫參數時少寫一個參數

    def edit_model(self, pk, fields, wheres='', returning=''):
        """編輯單條數據庫記錄"""
        if not pk:
            return {}
        elif wheres:
            wheres = self.__pk_name + ' = ' + str(id) + ' and ' + wheres
        else:
            wheres = self.__pk_name + ' = ' + str(id)

        return self.edit(fields, wheres, returning)

  有些朋友可能會奇怪,這里都知道主健了,為什么還要增加wheres條件呢?這是因為,我們在更新一些記錄時,比如說更新訂單,我們雖然知道訂單的主鍵值,但這個訂單並不一定就屬於這個用戶的,或者是該訂單指定狀態才能進行相關的操作,否則不能修改,這時我們就可以直接添加條件值來進行更新,如果條件不成立時則更新失敗

 

  前面的接口我們也改造一下

 1 @put('/api/product/<id:int>/')
 2 def callback(id):
 3     """
 4     修改記錄
 5     """
 6     name = web_helper.get_form('name', '產品名稱')
 7     code = web_helper.get_form('code', '產品編碼')
 8     product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '產品分類'))
 9     standard = web_helper.get_form('standard', '產品規格')
10     quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保質期')
11     place_of_origin = web_helper.get_form('place_of_origin', '產地')
12     front_cover_img = web_helper.get_form('front_cover_img', '封面圖片')
13     content = web_helper.get_form('content', '產品描述', is_check_special_char=False)
14     # 防sql注入攻擊處理
15     content = string_helper.filter_str(content, "'")
16     # 防xss攻擊處理
17     content = string_helper.clear_xss(content)
18     is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否啟用'))
19 
20     # 設置新增參數
21     fields = {
22         'name': string(name),
23         'code': string(code),
24         'product_class_id': product_class_id,
25         'standard': string(standard),
26         'quality_guarantee_period': string(quality_guarantee_period),
27         'place_of_origin': string(place_of_origin),
28         'front_cover_img': string(front_cover_img),
29         'content': string(content),
30         'is_enable': is_enable,
31     }
32     # 實例化product表操作類ProductLogic
33     _product_logic = product_logic.ProductLogic()
34     # 修改記錄
35     result = _product_logic.edit_model(id, fields)
36     # 判斷是否提交成功
37     if result:
38         return web_helper.return_msg(0, '成功')
39     else:
40         return web_helper.return_msg(-1, "提交失敗")

 

 

版權聲明:本文原創發表於 博客園,作者為 AllEmpty 本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。

python開發QQ群:669058475(本群已滿)、733466321(可以加2群)    作者博客:http://www.cnblogs.com/EmptyFS/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM