接下来我们要封装的是修改记录模块。
先上产品信息编辑接口代码
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/