zoukankan      html  css  js  c++  java
  • 我的第一个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/

  • 相关阅读:
    你不知道的多重循环的事情
    【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 &amp; 纹理混合
    ssh 远程登陆指定port
    GMT和CST的转换
    Swift新手教程系列5-函数+selector在swift中的使用方法
    Mac OS X 10.10, Eclipse+ADT真机调试代码时,Device Chooser中不显示真机的解决方式
    android studio 0.8.1使用和遇到问题解决
    C语言之函数调用17—递归法之中的一个般函数的调用(2)
    C语言之基本算法25—牛顿迭代法求方程近似根
    FineUI之使用SQL脚本从数据库表中生成对应的输入控件
  • 原文地址:https://www.cnblogs.com/EmptyFS/p/9462427.html
Copyright © 2011-2022 走看看