我的第一个python web开发框架(29)——定制ORM(五)
接下来我们要封装的是修改记录模块。
先上产品信息编辑接口代码
@put('/api/product/<id:int>/')
def callback(id):
"""
修改记录
"""
name = web_helper.get_form('name', '产品名称')
code = web_helper.get_form('code', '产品编码')
product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '产品分类'))
standard = web_helper.get_form('standard', '产品规格')
quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保质期')
place_of_origin = web_helper.get_form('place_of_origin', '产地')
front_cover_img = web_helper.get_form('front_cover_img', '封面图片')
content = web_helper.get_form('content', '产品描述', is_check_special_char=False)
# 防sql注入攻击处理
content = string_helper.filter_str(content, "'")
# 防xss攻击处理
content = string_helper.clear_xss(content)
is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否启用')) # 组成编辑Sql
sql = """
update product
set name=%s, code=%s, product_class_id=%s, standard=%s, quality_guarantee_period=%s,
place_of_origin=%s, front_cover_img=%s, content=%s, is_enable=%s
where id=%s returning id"""
vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content, is_enable, id)
# 写入数据库
result = db_helper.write(sql, vars)
29 # 判断是否提交成功
if result and result[0].get('id'):
return web_helper.return_msg(0, '成功')
else:
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"
完整代码
def edit(self, fields, wheres='', returning=''):
"""批量编辑数据库记录"""
### 拼接sql语句 ###
# 拼接字段与值
field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
# 设置sql拼接字典
parameter = {
'table_name': self.__table_name,
'field_list': ','.join(field_list)
}
# 如果存在更新条件,则将条件添加到sql拼接更换字典中
if wheres:
parameter['wheres'] = ' where ' + wheres
else:
parameter['wheres'] = '' # 如果有指定返回参数,则添加
if returning:
parameter['returning'] = ', ' + returning
else:
parameter['returning'] = '' # 生成sql语句
sql = "update %(table_name)s set %(field_list)s %(wheres)s returning id %(returning)s" % parameter
sql = sql % fields 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条件呢?这是因为,我们在更新一些记录时,比如说更新订单,我们虽然知道订单的主键值,但这个订单并不一定就属于这个用户的,或者是该订单指定状态才能进行相关的操作,否则不能修改,这时我们就可以直接添加条件值来进行更新,如果条件不成立时则更新失败
前面的接口我们也改造一下
@put('/api/product/<id:int>/')
def callback(id):
"""
修改记录
"""
name = web_helper.get_form('name', '产品名称')
code = web_helper.get_form('code', '产品编码')
product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '产品分类'))
standard = web_helper.get_form('standard', '产品规格')
quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保质期')
place_of_origin = web_helper.get_form('place_of_origin', '产地')
front_cover_img = web_helper.get_form('front_cover_img', '封面图片')
content = web_helper.get_form('content', '产品描述', is_check_special_char=False)
# 防sql注入攻击处理
content = string_helper.filter_str(content, "'")
# 防xss攻击处理
content = string_helper.clear_xss(content)
is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否启用')) # 设置新增参数
fields = {
'name': string(name),
'code': string(code),
'product_class_id': product_class_id,
'standard': string(standard),
'quality_guarantee_period': string(quality_guarantee_period),
'place_of_origin': string(place_of_origin),
'front_cover_img': string(front_cover_img),
'content': string(content),
'is_enable': is_enable,
}
# 实例化product表操作类ProductLogic
_product_logic = product_logic.ProductLogic()
# 修改记录
result = _product_logic.edit_model(id, fields)
# 判断是否提交成功
if result:
return web_helper.return_msg(0, '成功')
else:
return web_helper.return_msg(-1, "提交失败")
版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
python开发QQ群:669058475(本群已满)、733466321(可以加2群) 作者博客:http://www.cnblogs.com/EmptyFS/
我的第一个python web开发框架(29)——定制ORM(五)的更多相关文章
- 我的第一个python web开发框架(41)——总结
我的第一个python web开发框架系列博文从17年6.7月份开始写(存了近十章稿留到9月份才开始发布),到今天结束,一年多时间,想想真不容易啊. 整个过程断断续续,中间有段时间由于工作繁忙停了好长 ...
- 我的第一个python web开发框架(14)——后台管理系统登录功能
接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...
- 我的第一个python web开发框架(1)——前言
由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...
- 我的第一个python web开发框架(3)——怎么开始?
小白与小美公司经过几次接触商谈,好不容易将外包签订了下来,准备开始大干一场.不过小白由于没有太多的项目经验,学过python懂得python的基本语法,在公司跟着大家做过简单功能,另外还会一些HTML ...
- 我的第一个python web开发框架(22)——一个安全小事故
在周末的一个早上,小白还在做着美梦,就收到了小美的连环追魂call,电话一直响个不停. 小白打着哈欠拿起电话:早上好美女. 小美:出事了出事了,我们公司网站一早访问是一片空白,什么内容都没有了,你赶急 ...
- 我的第一个python web开发框架(2)——一个简单的小外包
第一部分说明 第一部分大概有20来章,主要讲的是一些开发常识.开发前中后期准备内容.开发环境与服务器部署环境安装设置.python基础框架结构与功能等内容,代码会比较简单. 本系列会以故事的方式,向大 ...
- 我的第一个python web开发框架(6)——第一个Hello World
小白中午听完老菜讲的那些话后一直在思考,可想来想去还是一头雾水,晕晕呼呼的一知半解,到最后还是想不明白,心想:老大讲的太高深了,只能听懂一半半,看来只能先记下来,将明白的先做,不明白的等以后遇到再学. ...
- 我的第一个python web开发框架(7)——本地部署前端访问服务器
PS:本系列内容进度节奏会放的很慢,每次知识点都尽量少一点,这样大家接触的知识点少了,会更容易理解,因为少即是多.另外,对于后面代码部分,虽然尽量不用那些复杂的封装和类,但它并不表示看了就能全部记住, ...
- 我的第一个python web开发框架(10)——工具函数包说明(一)
PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...
随机推荐
- Solaris 11 配置IP地址
查看ipipadm show-addr 删除IP地址ipadm delete-addr net0/v4 配置IP地址ipadm create-addr –T static –a local=10.90 ...
- 『ice 离散化广搜』
ice(USACO) Description Bessie 在一个冰封的湖面上游泳,湖面可以表示为二维的平面,坐标范围是-1,000,000,000..1,000,000,000. 湖面上的N(1 & ...
- Spring系列之手写一个SpringMVC
目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 Spring系列之AOP的原理及手动实现 Spring系列之手写注解与配置文件的解析 引言 在前面的几个章节中我 ...
- tensorflow机器学习模型的跨平台上线
在用PMML实现机器学习模型的跨平台上线中,我们讨论了使用PMML文件来实现跨平台模型上线的方法,这个方法当然也适用于tensorflow生成的模型,但是由于tensorflow模型往往较大,使用无法 ...
- Linux常用监控命令简介 - top
top -hv | -bcisS -d delay -n iterations -p pid [, pid ...] 指令介绍-b : 批次模式运行.-c : 显示执行任务的命令行.-d : 设定延迟 ...
- 变量内容的删除、取代与替换 (Optional)
变量除了可以直接设置来修改原本的内容之外,有没有办法通过简单的动作来将变量的内容进行微调呢? 举例来说,进行变量内容的删除.取代与替换等!是可以的!我们可以通过几个简单的小步骤来进行变量内容的微调喔! ...
- Mysql 连接数,最大并发数设置
项目中可能会遇到MySQL: ERROR 1040: Too many connections”的异常情况,造成这种情况的一种原因是访问量过高,MySQL服务器抗不住,这个时候就要考虑增加从服务器分散 ...
- C# 给现有PDF文档添加页眉、页脚
概述 页眉页脚是一篇完整.精致的文档的重要组成部分.在页眉页脚处,可以呈现的内容很多,如公司名称.页码.工作表名.日期.图片,如LOGO.标记等.在之前的文章中介绍了如何通过新建一页空白PDF页来添加 ...
- java学习笔记 线程的实现与同步
2019.4.2 线程实现的两种方式 继承线程,复写其中的run方法 实现runnable接口,复写run方法 使用: MyThread target = new MyThread(); new Th ...
- C# 定时器-System.Timers.Timer
using Newtonsoft.Json; using Rafy; using Rafy.Domain; using System; using System.Collections.Generic ...