个人第一个python web开发框架(29)——定制ORM(五)

  接下来咱们要封装的是修改记录模块。python

  先上产品信息编辑接口代码web

 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语句。sql

  操做步骤:数据库

  1.将新增记录时的字段名与值,使用字典方式存储起来api

  2.将字典作为参数传给ORM编辑记录方法数组

  3.编辑记录方法接收到参数之后,使用for循环,将字段名提取出来,生成sql编辑字段名、数组和字典替换数组,即:update table_name set 字段名=值,字段名=值... where 条件,这里须要将字典中的字段名提取出来组合成“字段名=值,字段名=值...”这样的串app

  这个步骤看起来跟新增记录差很少,只是生成sql的结果不同而已。xss

 

  一样的,咱们看看产品记录编辑的例子,方便进行理解post

  例如:咱们须要修改产品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/

相关文章
相关标签/搜索