几个复杂的ORM方式都已介绍完了,剩下一些常用的删除、获取记录数量、统计合计数、获取最大值、获取最小值等方法我就不一一详细介绍了,直接给出代码大家自行查看。

1 #!/usr/bin/env python

2 #coding=utf-8

3

4 from common importdb_helper5

6

7 classLogicBase():8 """逻辑层基础类"""

9

10 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):11 """类初始化"""

12 #数据库参数

13 self.__db =db14 #是否输出执行的Sql语句到日志中

15 self.__is_output_sql =is_output_sql16 #表名称

17 self.__table_name =str(table_name).lower()18 #查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式

19 self.__column_name_list =str(column_name_list).lower()20 #主健名称

21 self.__pk_name =str(pk_name).lower()22

23 #####################################################################

24 ### 执行Sql ###

25

26 defselect(self, sql):27 """执行sql查询语句(select)"""

28 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:29 #执行sql语句

30 result =db.execute(sql)31 if notresult:32 result =[]33 returnresult34

35 defexecute(self, sql):36 """执行sql语句,并提交事务"""

37 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:38 #执行sql语句

39 result =db.execute(sql)40 ifresult:41 db.commit()42 else:43 result =[]44 returnresult45

46 defcopy(self, values, columns):47 """批量更新数据"""

48 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:49 #执行sql语句

50 result = db.copy(values, self.__table_name, columns)51 returnresult52

53 defget_model(self, wheres):54 """通过条件获取一条记录"""

55 #如果有条件,则自动添加where

56 ifwheres:57 wheres = 'where' +wheres58

59 #合成sql语句

60 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" %\61 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}62 #初化化数据库链接

63 result =self.select(sql)64 ifresult:65 returnresult[0]66 return{}67

68 def get_model_for_pk(self, pk, wheres=''):69 """通过主键值获取数据库记录实体"""

70 if notpk:71 return{}72 #组装查询条件

73 wheres = '%s = %s' % (self.__pk_name, str(pk))74

75 returnself.get_model(wheres)76

77 def get_value(self, column_name, wheres=''):78 """

79 获取指定条件的字段值————多于条记录时,只取第一条记录80 :param column_name: 单个字段名,如:id81 :param wheres: 查询条件82 :return: 7 (指定的字段值)83 """

84 if notcolumn_name:85 returnNone86 elifwheres:87 wheres = 'where' +wheres88

89 sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' %\90 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}91 result =self.select(sql)92 #如果查询成功,则直接返回记录字典

93 ifresult:94 returnresult[0].get(column_name)95

96 def get_value_list(self, column_name, wheres=''):97 """

98 获取指定条件记录的字段值列表99 :param column_name: 单个字段名,如:id100 :param wheres: 查询条件101 :return: [1,3,4,6,7]102 """

103 if notcolumn_name:104 column_name = self.__pk_name

105 elifwheres:106 wheres = 'where' +wheres107

108 sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' %\109 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}110 result =self.select(sql)111 #如果查询失败或不存在指定条件记录,则直接返回初始值

112 if result andisinstance(result, list):113 return result[0].get('list')114 else:115 return[]116

117 def add_model(self, fields, returning=''):118 """新增数据库记录"""

119 ### 拼接sql语句 ###

120 #初始化变量

121 key_list =[]122 value_list =[]123 #将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组

124 #PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串

125 #比如:

126 #传入的字典为: {'id': 1, 'name': '名称'}

127 #那么生成的key_list为:'id','name'

128 #而value_list为:'%(id)s,%(name)s'

129 #最终而value_list为字符串对应名称位置会被替换成相应的值

130 for key infields.keys():131 key_list.append(key)132 value_list.append('%(' + key + ')s')133 #设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串

134 parameter ={135 'table_name': self.__table_name,136 'pk_name': self.__pk_name,137 'key_list': ','.join(key_list),138 'value_list': ','.join(value_list)139 }140 #如果有指定返回参数,则添加

141 ifreturning:142 parameter['returning'] = ',' +returning143 else:144 parameter['returning'] = ''

145

146 #生成可以使用字典替换的字符串

147 sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" %parameter148 #将生成好的字符串替字典参数值,生成最终可执行的sql语句

149 sql = sql %fields150

151 result =self.execute(sql)152 ifresult:153 returnresult[0]154 return{}155

156 def edit(self, fields, wheres='', returning=''):157 """批量编辑数据库记录"""

158 ### 拼接sql语句 ###

159 #拼接字段与值

160 field_list = [key + '= %(' + key + ')s' for key infields.keys()]161 #设置sql拼接字典

162 parameter ={163 'table_name': self.__table_name,164 'pk_name': self.__pk_name,165 'field_list': ','.join(field_list)166 }167 #如果存在更新条件,则将条件添加到sql拼接更换字典中

168 ifwheres:169 parameter['wheres'] = 'where' +wheres170 else:171 parameter['wheres'] = ''

172

173 #如果有指定返回参数,则添加

174 ifreturning:175 parameter['returning'] = ',' +returning176 else:177 parameter['returning'] = ''

178

179 #生成sql语句

180 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter181 sql = sql %fields182

183 returnself.execute(sql)184

185 def edit_model(self, pk, fields, wheres='', returning=''):186 """编辑单条数据库记录"""

187 if notpk:188 return{}189 elifwheres:190 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres191 else:192 wheres = self.__pk_name + '=' +str(pk)193

194 returnself.edit(fields, wheres, returning)195

196 def delete(self, wheres='', returning='', is_update_cache=True):197 """批量删除数据库记录"""

198 #如果存在条件

199 ifwheres:200 wheres = 'where' +wheres201

202 #如果有指定返回参数,则添加

203 ifreturning:204 returning = ',' +returning205

206 #生成sql语句

207 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\208 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}209 returnself.execute(sql)210

211 def delete_model(self, pk, wheres='', returning='', is_update_cache=True):212 """删除单条数据库记录"""

213 if notpk:214 return{}215 elifwheres:216 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres217 else:218 wheres = self.__pk_name + '=' +str(pk)219

220 returnself.delete(wheres, returning)221

222 def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):223 """

224 获取指定条件的数据库记录集225 :param column_name_list: 查询字段226 :param wheres: 查询条件227 :param page_number: 分页索引值228 :param page_size: 分页大小, 存在值时才会执行分页229 :param orderby: 排序规则230 :param table_name: 查询数据表,多表查询时需要设置231 :return: 返回记录集总数量与分页记录集232 {'records': 0, 'total': 0, 'page': 0, 'rows': []}233 """

234 #初始化输出参数:总记录数量与列表集

235 data ={236 'records': 0, #总记录数

237 'total': 0, #总页数

238 'page': 1, #当前页面索引

239 'rows': [], #查询结果(记录列表)

240 }241 #初始化查询数据表名称

242 if nottable_name:243 table_name = self.__table_name

244 #初始化查询字段名

245 if notcolumn_name_list:246 column_name_list = self.__column_name_list

247 #初始化查询条件

248 ifwheres:249 #如果是字符串,表示该查询条件已组装好了,直接可以使用

250 ifisinstance(wheres, str):251 wheres = 'where' +wheres252 #如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用

253 elifisinstance(wheres, list):254 wheres = 'where' + 'and'.join(wheres)255 #初始化排序

256 if notorderby:257 orderby = self.__pk_name + 'desc'

258 #初始化分页查询的记录区间

259 paging = ''

260

261 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:262 #############################################################

263 #判断是否需要进行分页

264 if not page_size isNone:265 ### 执行sql,获取指定条件的记录总数量

266 sql = 'select count(1) as records from %(table_name)s %(wheres)s' %\267 {'table_name': table_name, 'wheres': wheres}268 result =db.execute(sql)269 #如果查询失败或不存在指定条件记录,则直接返回初始值

270 if not result or result[0]['records'] ==0:271 returndata272

273 #设置记录总数量

274 data['records'] = result[0].get('records')275

276 #########################################################

277 ### 设置分页索引与页面大小 ###

278 if page_size <=0:279 page_size = 10

280 #计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量

281 if data['records'] % page_size ==0:282 page_total = data['records'] //page_size283 else:284 page_total = data['records'] // page_size + 1

285 #判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页

286 if page_number < 1 or page_number >page_total:287 page_number =page_total288 #记录总页面数量

289 data['total'] =page_total290 #记录当前页面值

291 data['page'] =page_number292 #计算当前页面要显示的记录起始位置(limit指定的位置)

293 record_number = (page_number - 1) *page_size294 #设置查询分页条件

295 paging = 'limit' + str(page_size) + 'offset' +str(record_number)296 #############################################################

297

298 ### 按条件查询数据库记录

299 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" %\300 {'column_name_list': column_name_list,301 'table_name': table_name,302 'wheres': wheres,303 'orderby': orderby,304 'paging': paging}305 result =db.execute(sql)306 ifresult:307 data['rows'] =result308 #不需要分页查询时,直接在这里设置总记录数

309 if page_size isNone:310 data['records'] =len(result)311

312 returndata313

314 def get_count(self, wheres=''):315 """获取指定条件记录数量"""

316 ifwheres:317 wheres = 'where' +wheres318 sql = 'select count(1) as total from %(table_name)s %(wheres)s' %\319 {'table_name': self.__table_name, 'wheres': wheres}320 result =self.select(sql)321 #如果查询存在记录,则返回true

322 ifresult:323 return result[0].get('total')324 return0325

326 defget_sum(self, fields, wheres):327 """获取指定条件记录数量"""

328 sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s' %\329 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}330 result =self.select(sql)331 #如果查询存在记录,则返回true

332 if result and result[0].get('total'):333 return result[0].get('total')334 return0335

336 defget_min(self, fields, wheres):337 """获取该列记录最小值"""

338 sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s' %\339 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}340 result =self.select(sql)341 #如果查询存在记录,则返回true

342 if result and result[0].get('min'):343 return result[0].get('min')344

345 defget_max(self, fields, wheres):346 """获取该列记录最大值"""

347 sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s' %\348 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}349 result =self.select(sql)350 #如果查询存在记录,则返回true

351 if result and result[0].get('max'):352 return result[0].get('max')353

354 #####################################################################

View Code

大家只要掌握了ORM简单的组合sql方法,就可以自由发挥,根据自己的需要去创建不同的方法了,也可以随意更换mysql、mssql等数据库。

当然,这只是最简单的ORM方式,提交字段参数和条件参数时,它不会自动分辨字段的类型,不会自动初始化默认值,如果想让它变的更加强大,还需要做更多的改造与处理,这样做的话它也会跟着变的更加复杂和难懂,性能也会跟着下降。不过当前功能对于多数项目来说,已经足够使用了。大家如果有需要可以自行研究进行扩展。

在日常操作中,获取指定记录实体是最常见使用最频繁的操作,为了减少对数据库的查询,我们可以将ORM与Nosql结合起来,提升ORM的操作性能,当然如果你不想使用nosql缓存,也可以直接跳过本章节。

使用Nosql,首先我们需要一个链接Nosql的配置文件,用它来存储Nosql的服务地址、端口、密码等参数

在config文件夹中我们创建redis_config.py配置文件

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

### redis缓存配置参数 ###

REDIS ={#服务地址

'server': '127.0.0.1',#服务端口

'post': 6379,#服务密码

'pwd': '',#数据库序号

'db': 1}

然后我们还需要一个nosql链接工具包(cache_helper.py),用来对nosql进行set、get、delete和clear操作(存储、获取、删除和清空缓存)

1 #!/usr/bin/env python

2 #coding=utf-8

3

4 importredis5

6 from common importlog_helper7 from config importredis_config8

9 #设置redis配置参数

10 _redis =redis_config.REDIS11 #初始化Redis缓存链接

12 r =None13 try:14 if notr:15 r = redis.Redis(host=_redis.get('server', ''),16 port=_redis.get('post', ''),17 db=_redis.get('db', ''),18 password=_redis.get('pwd', ''),19 socket_timeout=1,20 socket_connect_timeout=1)21 exceptException as e:22 log_helper.info('连接redis出错:(' + str(_redis) + ')' +str(e.args))23 pass

24

25

26 def set(key, value, time=86400):27 """

28 写缓存29 :param key: 缓存key,字符串,不区分大小写30 :param value: 要存储的值31 :param time: 缓存过期时间(单位:秒),0=永不过期32 :return:33 """

34 #将key转换为小写字母

35 key =str(key).lower()36 try:37 r.set(key, value, time)38 exceptException as e:39 log_helper.info('写缓存失败:key(' + key + ')' +str(e.args))40 pass

41

42

43 defget(key):44 """

45 读缓存46 :param key: 缓存key,字符串,不区分大小写47 :return:48 """

49 #将key转换为小写字母

50 key =str(key).lower()51 try:52 value =r.get(key)53 exceptException as e:54 #log_helper.error('读缓存失败:key(' + key + ')' + str(e.args) + ' r:' + str(r) + ' _redis:' + str(_redis))

55 value =None56

57 return_str_to_json(value)58

59

60 defpush(key, value):61 """

62 添加数据到队列头部63 :param key: 缓存key,字符串,不区分大小写64 :param value: 要存储的值65 """

66 #将key转换为小写字母

67 key =str(key).lower()68 try:69 r.lpush(key, value)70 exceptException as e:71 log_helper.info('写缓存失败:key(' + key + ')' +str(e.args))72 pass

73

74

75 defpop(key):76 """

77 从缓存队列的后尾读取一条数据78 :param key: 缓存key,字符串,不区分大小写79 :return: 缓存数据80 """

81 #将key转换为小写字母

82 key =str(key).lower()83 try:84 value =r.rpop(key)85 exceptException as e:86 log_helper.info('读取缓存队列失败:key(' + key + ')' +str(e.args))87 value =None88

89 return_str_to_json(value)90

91

92 def_str_to_json(value):93 """

94 将缓存中读取出来的字符串转换成对应的数据、元组、列表或字典95 """

96 if notvalue:97 returnvalue98 #否则直接转换

99 try:100 value =value.decode()101 returneval(value)102 exceptException as e:103 print(e.args)104 pass

105 #否则直接输出字符串

106 returnvalue107

108

109 defdelete(key):110 """

111 删除缓存112 :param key:缓存key,字符串,不区分大小写113 :return:114 """

115 #将key转换为小写字母

116 key =str(key).lower()117 try:118 log_helper.info(str(r.delete(key)))119 exceptException as e:120 log_helper.info('Exception:' +str(e.args))121 pass

122

123

124 defclear():125 """

126 清空所有缓存127 """

128 try:129 r.flushdb()130 except:131 pass

View Code

我常用的是redis,所以使用cache_helper.py时,需要安装redis服务和对应的Python包。如果你使用的是memcache,你只需要重构一下cache_helper.py代码就可以了。

接下来我们改造一下逻辑层基类(ORM模块)

首先我们需要导入cache_helper

from common import db_helper, cache_helper

在使用nosql缓存时,大家都知道我们是使用key来进行对象存取的,而这个key也是唯一的,所以key的生成就很重要的,为了避免key的重复,我们在对记录设置key时,可以用表名+主键id的方式来组合key,当然为了调用方便,可以将获取key写成一个方法来生成

defget_cache_key(self, pk):"""获取缓存key值"""

return ''.join((self.__table_name, '_', str(pk)))

这里使用join的方法,将表名、下横线、主键值组合生成缓存key字符串

对于缓存的操作,主要有设置缓存、获取缓存、删除缓存这三种操作,当然为了方便我们获取记录中指定字段值,我们可以增加读取指定字段值方法。

首先是设置缓存方法,大家看看下面代码,它非常简单,先调用生成缓存key,然后将对象存储到缓存中,并指定过期时间,当设置time为0时,它将永不过期

def set_model_for_cache(self, pk, value, time=43200):"""更新存储在缓存中的数据库记录,缓存过期时间为12小时"""

#生成缓存key

key =self.get_cache_key(pk)#存储到nosql缓存中

cache_helper.set(key, value, time)

接着是获取缓存对象方法

defget_model_for_cache(self, pk):"""从缓存中读取数据库记录"""

#生成缓存key

key =self.get_cache_key(pk)#从缓存中读取数据库记录

result =cache_helper.get(key)#缓存中不存在记录,则从数据库获取

if notresult:

result=self.get_model_for_pk(pk)

self.set_model_for_cache(pk, result)ifresult:returnresultelse:return {}

我们首先要做的同样是生成缓存key,然后调用get方法从缓存中读取对象,执行完后,需要判断该对象是否存在缓存中,如果不存在则表示该对象并未存储到缓存中或它可能存储过期了,所以需要重新从数据库中读取出来,并将它存储到缓存中,然后将读取出来的记录实体返回出去。

然后我们再增加一个读取指定记录字段值的方法

defget_value_for_cache(self, pk, column_name):"""获取指定记录的字段值"""

return self.get_model_for_cache(pk).get(column_name)

它直接调用获取缓存对象方法,然后从返回的对象中读取指定的字段值就可以了

删除缓存方法也很简单,生成缓存key后,直接调用delete进行删除。对于删除方法,有时候调用不知是不是nosql自身bug问题,还是在主从关系的nosql中读写分离会引起删除失败,如果出现这种情况,可以将delete改为set,将该缓存set为空就可以解决这个问题

defdel_model_for_cache(self, pk):"""删除缓存中指定数据"""

#生成缓存key

key =self.get_cache_key(pk)#log_helper.info(key)

#存储到nosql缓存中

cache_helper.delete(key)

PS:在使用缓存操作时,有时我们直接对数据库进行操作,就会引起数据与缓存不匹配,出现脏数据的情况,这时在后台增加清空缓存的操作,直接调用cache_helper.clear()进行清空缓存。

基本方法都完成了,接下来就是要对ORM的删除与修改方法进行改造了,让它们自行根据需要对缓存进行对应操作,让缓存与数据表中的记录保持一致。

在改造时,我们只需要对删除与修改操作进行处理,对新增与查询操作不需要操作,因为新增的记录,它并在缓存中并不存在,所以不需要进行操作,而查询也不会改变数据内容,只有进行删除和修改操作时,才会变动数据内容,这时就需要更改缓存,让数据保持一致。

改造编辑记录实体方法

1 def edit(self, fields, wheres='', returning='', is_update_cache=True):2 """

3 批量编辑数据库记录4 :param fields: 要更新的字段(字段名与值存储在字典中)5 :param wheres: 更新条件6 :param returning: 更新成功后,返回的字段名7 :param is_update_cache: 是否同步更新缓存8 :return:9 """

10 ### 拼接sql语句 ###

11 #拼接字段与值

12 field_list = [key + '= %(' + key + ')s' for key infields.keys()]13 #设置sql拼接字典

14 parameter ={15 'table_name': self.__table_name,16 'pk_name': self.__pk_name,17 'field_list': ','.join(field_list)18 }19 #如果存在更新条件,则将条件添加到sql拼接更换字典中

20 ifwheres:21 parameter['wheres'] = 'where' +wheres22 else:23 parameter['wheres'] = ''

24

25 #如果有指定返回参数,则添加

26 ifreturning:27 parameter['returning'] = ',' +returning28 else:29 parameter['returning'] = ''

30

31 #生成sql语句

32 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter33 sql = sql %fields34

35 result =self.execute(sql)36 ifresult:37 #判断是否删除对应的缓存

38 ifis_update_cache:39 #循环删除更新成功的所有记录对应的缓存

40 for model inresult:41 self.del_model_for_cache(model.get('id', 0))42 return result

大家可以看到,该方法增加了is_update_cache 是否同步更新缓存参数,这是因为我们在使用缓存时会存在一些特殊情况,比如说批量更新很多数据时,如果使用循环逐条清理对应缓存时,会占用较多资源,我们可以关掉缓存的同步更新,直接调用clear清空所有缓存会更加快捷;又比如说,页面访问数的更新,它会更新的非常频繁,我们不需要实时清除,可以使用其他方式触发清理,也可以将点击数用独立缓存存储使用等

而清理缓存,我们只需要将缓存内容直接删除就可以了,因为执行更新以后,返回的记录实体没有设置为*时,只返回主键id,直接设置的话会造成缓存数据丢失细节的问题,另外,我们执行更新以后,该记录也不一定还会被读取出来。

删除记录也进行一样的改造

1 def delete(self, wheres='', returning='', is_update_cache=True):2 """

3 批量删除数据库记录4 :param wheres: 删除条件5 :param returning: 删除成功后,返回的字段名6 :param is_update_cache: 是否同步更新缓存7 :return:8 """

9 #如果存在条件

10 ifwheres:11 wheres = 'where' +wheres12

13 #如果有指定返回参数,则添加

14 ifreturning:15 returning = ',' +returning16

17 #生成sql语句

18 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\19 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}20 result =self.execute(sql)21 ifresult:22 #同步删除对应的缓存

23 ifis_update_cache:24 for model inresult:25 self.del_model_for_cache(model.get('id', 0))26 return result

对于缓存基本上就这两个要进行改造的操作了。在实现开发中,我们认真想一想,其实我们还会存在一些特殊的情况,比如说我们对数据进行加工处理后,将加工后的值存储到缓存中,而对相关记录进行修改或删除操作以后,由于这些缓存它与记录并没有关联,所以执行相关操作以后,它就变成孤岛,不会实时同步,产生脏数据。所以我们需要有一个功能,可以将它们管理起来,与该数据表的修改和删除操作关联起来,进行修改和删除操作后同步清除这些特殊缓存。

根据这些要求,我们就需要再增加两个缓存操作方法,用来存储这些特殊的缓存名称,然后在进行修改和删除操作时,同步清除这些特殊缓存。

首先我们需要在初始化方法中,添加一个绑定该数据表的全局缓存变量self.__cache_list,它由表名称+_cache_list组成。

1 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):2 """类初始化"""

3 #数据库参数

4 self.__db =db5 #是否输出执行的Sql语句到日志中

6 self.__is_output_sql =is_output_sql7 #表名称

8 self.__table_name =str(table_name).lower()9 #查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式

10 self.__column_name_list =str(column_name_list).lower()11 #主健名称

12 self.__pk_name =str(pk_name).lower()13 #缓存列表

14 self.__cache_list = self.__table_name + '_cache_list'

然后我们再添加特殊缓存存储方法

1 defadd_relevance_cache_in_list(self, key):2 """将缓存名称存储到列表里————主要存储与记录变更关联的"""

3 #从nosql中读取全局缓存列表

4 cache_list = cache_helper.get(self.__cache_list)5 #判断缓存列表是否有值,有则进行添加操作

6 ifcache_list:7 #判断是否已存储列表中,不存在则执行添加操作

8 if not key incache_list:9 cache_list.append(key)10 cache_helper.set(self.__cache_list, cache_list)11 #无则直接创建全局缓存列表,并存储到nosql中

12 else:13 cache_list =[key]14 cache_helper.set(self.__cache_list, cache_list)

执行该方法,会将我们自定义的缓存名称存储到全局缓存变量中

接着我们再添加一个清除所有特殊缓存的方法

1 defdel_relevance_cache(self):2 """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""

3 #从nosql中读取全局缓存列表

4 cache_list = cache_helper.get(self.__cache_list)5 #清除已删除缓存列表

6 cache_helper.delete(self.__cache_list)7 ifcache_list:8 #执行删除操作

9 for cache incache_list:10 cache_helper.delete(cache)

添加完成以后,我们再来改造一下修改与删除代码,只需要在里面添加清除所有特殊缓存方法就可以了

1 def edit(self, fields, wheres='', returning='', is_update_cache=True):2 """

3 批量编辑数据库记录4 :param fields: 要更新的字段(字段名与值存储在字典中)5 :param wheres: 更新条件6 :param returning: 更新成功后,返回的字段名7 :param is_update_cache: 是否同步更新缓存8 :return:9 """

10 ### 拼接sql语句 ###

11 #拼接字段与值

12 field_list = [key + '= %(' + key + ')s' for key infields.keys()]13 #设置sql拼接字典

14 parameter ={15 'table_name': self.__table_name,16 'pk_name': self.__pk_name,17 'field_list': ','.join(field_list)18 }19 #如果存在更新条件,则将条件添加到sql拼接更换字典中

20 ifwheres:21 parameter['wheres'] = 'where' +wheres22 else:23 parameter['wheres'] = ''

24

25 #如果有指定返回参数,则添加

26 ifreturning:27 parameter['returning'] = ',' +returning28 else:29 parameter['returning'] = ''

30

31 #生成sql语句

32 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter33 sql = sql %fields34

35 result =self.execute(sql)36 ifresult:37 #判断是否删除对应的缓存

38 ifis_update_cache:39 #循环删除更新成功的所有记录对应的缓存

40 for model inresult:41 self.del_model_for_cache(model.get('id', 0))42 #同步删除与本表关联的缓存

43 self.del_relevance_cache()44 returnresult45

46 def delete(self, wheres='', returning='', is_update_cache=True):47 """

48 批量删除数据库记录49 :param wheres: 删除条件50 :param returning: 删除成功后,返回的字段名51 :param is_update_cache: 是否同步更新缓存52 :return:53 """

54 #如果存在条件

55 ifwheres:56 wheres = 'where' +wheres57

58 #如果有指定返回参数,则添加

59 ifreturning:60 returning = ',' +returning61

62 #生成sql语句

63 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\64 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}65 result =self.execute(sql)66 ifresult:67 #同步删除对应的缓存

68 ifis_update_cache:69 for model inresult:70 self.del_model_for_cache(model.get('id', 0))71 #同步删除与本表关联的缓存

72 self.del_relevance_cache()73 return result

View Code

ORM的缓存改造就全部完成了,下面是完整代码

1 #!/usr/bin/env python

2 #coding=utf-8

3

4 from common importdb_helper, cache_helper5

6

7 classLogicBase():8 """逻辑层基础类"""

9

10 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):11 """类初始化"""

12 #数据库参数

13 self.__db =db14 #是否输出执行的Sql语句到日志中

15 self.__is_output_sql =is_output_sql16 #表名称

17 self.__table_name =str(table_name).lower()18 #查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式

19 self.__column_name_list =str(column_name_list).lower()20 #主健名称

21 self.__pk_name =str(pk_name).lower()22 #缓存列表

23 self.__cache_list = self.__table_name + '_cache_list'

24

25 #####################################################################

26 ### 执行Sql ###

27

28 defselect(self, sql):29 """执行sql查询语句(select)"""

30 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:31 #执行sql语句

32 result =db.execute(sql)33 if notresult:34 result =[]35 returnresult36

37 defexecute(self, sql):38 """执行sql语句,并提交事务"""

39 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:40 #执行sql语句

41 result =db.execute(sql)42 ifresult:43 db.commit()44 else:45 result =[]46 returnresult47

48 defcopy(self, values, columns):49 """批量更新数据"""

50 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:51 #执行sql语句

52 result = db.copy(values, self.__table_name, columns)53 returnresult54

55 defget_model(self, wheres):56 """通过条件获取一条记录"""

57 #如果有条件,则自动添加where

58 ifwheres:59 wheres = 'where' +wheres60

61 #合成sql语句

62 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" %\63 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}64 #初化化数据库链接

65 result =self.select(sql)66 ifresult:67 returnresult[0]68 return{}69

70 def get_model_for_pk(self, pk, wheres=''):71 """通过主键值获取数据库记录实体"""

72 if notpk:73 return{}74 #组装查询条件

75 wheres = '%s = %s' % (self.__pk_name, str(pk))76

77 returnself.get_model(wheres)78

79 def get_value(self, column_name, wheres=''):80 """

81 获取指定条件的字段值————多于条记录时,只取第一条记录82 :param column_name: 单个字段名,如:id83 :param wheres: 查询条件84 :return: 7 (指定的字段值)85 """

86 if notcolumn_name:87 returnNone88 elifwheres:89 wheres = 'where' +wheres90

91 sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' %\92 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}93 result =self.select(sql)94 #如果查询成功,则直接返回记录字典

95 ifresult:96 returnresult[0].get(column_name)97

98 def get_value_list(self, column_name, wheres=''):99 """

100 获取指定条件记录的字段值列表101 :param column_name: 单个字段名,如:id102 :param wheres: 查询条件103 :return: [1,3,4,6,7]104 """

105 if notcolumn_name:106 column_name = self.__pk_name

107 elifwheres:108 wheres = 'where' +wheres109

110 sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' %\111 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}112 result =self.select(sql)113 #如果查询失败或不存在指定条件记录,则直接返回初始值

114 if result andisinstance(result, list):115 return result[0].get('list')116 else:117 return[]118

119 def add_model(self, fields, returning=''):120 """新增数据库记录"""

121 ### 拼接sql语句 ###

122 #初始化变量

123 key_list =[]124 value_list =[]125 #将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组

126 #PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串

127 #比如:

128 #传入的字典为: {'id': 1, 'name': '名称'}

129 #那么生成的key_list为:'id','name'

130 #而value_list为:'%(id)s,%(name)s'

131 #最终而value_list为字符串对应名称位置会被替换成相应的值

132 for key infields.keys():133 key_list.append(key)134 value_list.append('%(' + key + ')s')135 #设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串

136 parameter ={137 'table_name': self.__table_name,138 'pk_name': self.__pk_name,139 'key_list': ','.join(key_list),140 'value_list': ','.join(value_list)141 }142 #如果有指定返回参数,则添加

143 ifreturning:144 parameter['returning'] = ',' +returning145 else:146 parameter['returning'] = ''

147

148 #生成可以使用字典替换的字符串

149 sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" %parameter150 #将生成好的字符串替字典参数值,生成最终可执行的sql语句

151 sql = sql %fields152

153 result =self.execute(sql)154 ifresult:155 returnresult[0]156 return{}157

158 def edit(self, fields, wheres='', returning='', is_update_cache=True):159 """

160 批量编辑数据库记录161 :param fields: 要更新的字段(字段名与值存储在字典中)162 :param wheres: 更新条件163 :param returning: 更新成功后,返回的字段名164 :param is_update_cache: 是否同步更新缓存165 :return:166 """

167 ### 拼接sql语句 ###

168 #拼接字段与值

169 field_list = [key + '= %(' + key + ')s' for key infields.keys()]170 #设置sql拼接字典

171 parameter ={172 'table_name': self.__table_name,173 'pk_name': self.__pk_name,174 'field_list': ','.join(field_list)175 }176 #如果存在更新条件,则将条件添加到sql拼接更换字典中

177 ifwheres:178 parameter['wheres'] = 'where' +wheres179 else:180 parameter['wheres'] = ''

181

182 #如果有指定返回参数,则添加

183 ifreturning:184 parameter['returning'] = ',' +returning185 else:186 parameter['returning'] = ''

187

188 #生成sql语句

189 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter190 sql = sql %fields191

192 result =self.execute(sql)193 ifresult:194 #判断是否删除对应的缓存

195 ifis_update_cache:196 #循环删除更新成功的所有记录对应的缓存

197 for model inresult:198 self.del_model_for_cache(model.get('id', 0))199 #同步删除与本表关联的缓存

200 self.del_relevance_cache()201 returnresult202

203 def edit_model(self, pk, fields, wheres='', returning=''):204 """编辑单条数据库记录"""

205 if notpk:206 return{}207 elifwheres:208 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres209 else:210 wheres = self.__pk_name + '=' +str(pk)211

212 returnself.edit(fields, wheres, returning)213

214 def delete(self, wheres='', returning='', is_update_cache=True):215 """

216 批量删除数据库记录217 :param wheres: 删除条件218 :param returning: 删除成功后,返回的字段名219 :param is_update_cache: 是否同步更新缓存220 :return:221 """

222 #如果存在条件

223 ifwheres:224 wheres = 'where' +wheres225

226 #如果有指定返回参数,则添加

227 ifreturning:228 returning = ',' +returning229

230 #生成sql语句

231 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\232 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}233 result =self.execute(sql)234 ifresult:235 #同步删除对应的缓存

236 ifis_update_cache:237 for model inresult:238 self.del_model_for_cache(model.get('id', 0))239 #同步删除与本表关联的缓存

240 self.del_relevance_cache()241 returnresult242

243 def delete_model(self, pk, wheres='', returning='', is_update_cache=True):244 """删除单条数据库记录"""

245 if notpk:246 return{}247 elifwheres:248 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres249 else:250 wheres = self.__pk_name + '=' +str(pk)251

252 returnself.delete(wheres, returning)253

254 def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):255 """

256 获取指定条件的数据库记录集257 :param column_name_list: 查询字段258 :param wheres: 查询条件259 :param page_number: 分页索引值260 :param page_size: 分页大小, 存在值时才会执行分页261 :param orderby: 排序规则262 :param table_name: 查询数据表,多表查询时需要设置263 :return: 返回记录集总数量与分页记录集264 {'records': 0, 'total': 0, 'page': 0, 'rows': []}265 """

266 #初始化输出参数:总记录数量与列表集

267 data ={268 'records': 0, #总记录数

269 'total': 0, #总页数

270 'page': 1, #当前页面索引

271 'rows': [], #查询结果(记录列表)

272 }273 #初始化查询数据表名称

274 if nottable_name:275 table_name = self.__table_name

276 #初始化查询字段名

277 if notcolumn_name_list:278 column_name_list = self.__column_name_list

279 #初始化查询条件

280 ifwheres:281 #如果是字符串,表示该查询条件已组装好了,直接可以使用

282 ifisinstance(wheres, str):283 wheres = 'where' +wheres284 #如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用

285 elifisinstance(wheres, list):286 wheres = 'where' + 'and'.join(wheres)287 #初始化排序

288 if notorderby:289 orderby = self.__pk_name + 'desc'

290 #初始化分页查询的记录区间

291 paging = ''

292

293 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:294 #############################################################

295 #判断是否需要进行分页

296 if not page_size isNone:297 ### 执行sql,获取指定条件的记录总数量

298 sql = 'select count(1) as records from %(table_name)s %(wheres)s' %\299 {'table_name': table_name, 'wheres': wheres}300 result =db.execute(sql)301 #如果查询失败或不存在指定条件记录,则直接返回初始值

302 if not result or result[0]['records'] ==0:303 returndata304

305 #设置记录总数量

306 data['records'] = result[0].get('records')307

308 #########################################################

309 ### 设置分页索引与页面大小 ###

310 if page_size <=0:311 page_size = 10

312 #计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量

313 if data['records'] % page_size ==0:314 page_total = data['records'] //page_size315 else:316 page_total = data['records'] // page_size + 1

317 #判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页

318 if page_number < 1 or page_number >page_total:319 page_number =page_total320 #记录总页面数量

321 data['total'] =page_total322 #记录当前页面值

323 data['page'] =page_number324 #计算当前页面要显示的记录起始位置(limit指定的位置)

325 record_number = (page_number - 1) *page_size326 #设置查询分页条件

327 paging = 'limit' + str(page_size) + 'offset' +str(record_number)328 #############################################################

329

330 ### 按条件查询数据库记录

331 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" %\332 {'column_name_list': column_name_list,333 'table_name': table_name,334 'wheres': wheres,335 'orderby': orderby,336 'paging': paging}337 result =db.execute(sql)338 ifresult:339 data['rows'] =result340 #不需要分页查询时,直接在这里设置总记录数

341 if page_size isNone:342 data['records'] =len(result)343

344 returndata345

346 def get_count(self, wheres=''):347 """获取指定条件记录数量"""

348 ifwheres:349 wheres = 'where' +wheres350 sql = 'select count(1) as total from %(table_name)s %(wheres)s' %\351 {'table_name': self.__table_name, 'wheres': wheres}352 result =self.select(sql)353 #如果查询存在记录,则返回true

354 ifresult:355 return result[0].get('total')356 return0357

358 defget_sum(self, fields, wheres):359 """获取指定条件记录数量"""

360 sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s' %\361 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}362 result =self.select(sql)363 #如果查询存在记录,则返回true

364 if result and result[0].get('total'):365 return result[0].get('total')366 return0367

368 defget_min(self, fields, wheres):369 """获取该列记录最小值"""

370 sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s' %\371 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}372 result =self.select(sql)373 #如果查询存在记录,则返回true

374 if result and result[0].get('min'):375 return result[0].get('min')376

377 defget_max(self, fields, wheres):378 """获取该列记录最大值"""

379 sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s' %\380 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}381 result =self.select(sql)382 #如果查询存在记录,则返回true

383 if result and result[0].get('max'):384 return result[0].get('max')385

386 #####################################################################

387

388

389 #####################################################################

390 ### 缓存操作方法 ###

391

392 defget_cache_key(self, pk):393 """获取缓存key值"""

394 return ''.join((self.__table_name, '_', str(pk)))395

396 def set_model_for_cache(self, pk, value, time=43200):397 """更新存储在缓存中的数据库记录,缓存过期时间为12小时"""

398 #生成缓存key

399 key =self.get_cache_key(pk)400 #存储到nosql缓存中

401 cache_helper.set(key, value, time)402

403 defget_model_for_cache(self, pk):404 """从缓存中读取数据库记录"""

405 #生成缓存key

406 key =self.get_cache_key(pk)407 #从缓存中读取数据库记录

408 result =cache_helper.get(key)409 #缓存中不存在记录,则从数据库获取

410 if notresult:411 result =self.get_model_for_pk(pk)412 self.set_model_for_cache(pk, result)413 ifresult:414 returnresult415 else:416 return{}417

418 defget_value_for_cache(self, pk, column_name):419 """获取指定记录的字段值"""

420 returnself.get_model_for_cache(pk).get(column_name)421

422 defdel_model_for_cache(self, pk):423 """删除缓存中指定数据"""

424 #生成缓存key

425 key =self.get_cache_key(pk)426 #log_helper.info(key)

427 #存储到nosql缓存中

428 cache_helper.delete(key)429

430 defadd_relevance_cache_in_list(self, key):431 """将缓存名称存储到列表里————主要存储与记录变更关联的"""

432 #从nosql中读取全局缓存列表

433 cache_list = cache_helper.get(self.__cache_list)434 #判断缓存列表是否有值,有则进行添加操作

435 ifcache_list:436 #判断是否已存储列表中,不存在则执行添加操作

437 if not key incache_list:438 cache_list.append(key)439 cache_helper.set(self.__cache_list, cache_list)440 #无则直接创建全局缓存列表,并存储到nosql中

441 else:442 cache_list =[key]443 cache_helper.set(self.__cache_list, cache_list)444

445 defdel_relevance_cache(self):446 """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""

447 #从nosql中读取全局缓存列表

448 cache_list = cache_helper.get(self.__cache_list)449 #清除已删除缓存列表

450 cache_helper.delete(self.__cache_list)451 ifcache_list:452 #执行删除操作

453 for cache incache_list:454 cache_helper.delete(cache)455

456 #####################################################################

View Code

版权声明:本文原创发表于 博客园,作者为

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

python开发框架 代码生成_我的第一个python web开发框架(31)——定制ORM(七)...相关推荐

  1. python开发框架 代码生成_我的第一个python web开发框架(28)——定制ORM(四)...

    在数据库操作时,新增记录也是必不可少的,接下来我们应用字典的特性来组合sql语句 先上产品新增接口代码 1 @post('/api/product/')2 defcallback():3 " ...

  2. python后台框架_我的第一个python web开发框架(14)——后台管理系统登录功能

    27 28 29 30 31 32 33  34 35 36 37 38 39  40 41 42 43 44 45 46 47 style="width:150px;"> ...

  3. TSS翻译:帮我选一个Java Web开发框架吧

    TSS:帮我选一个Java Web开发框架吧 最近 TheServerSide.com 上一篇文章引起了常常的讨论.地址见这里:Chose a web client framework. Cheste ...

  4. python爬酷狗音乐_良心推荐!一个Python高手必读的库,真香!

    菜鸟进阶高手,需要内外的修炼,外练招式,内修心法.招式有很多比如基本的函数,类,文件,模块,到并发,数据库的使用,再到一些框架的使用无论是爬虫的西瓜皮框架,还是后端的Django,Flask等等.内功 ...

  5. python中datetime库_一天掌握一个Python库--datetime库

    #一天掌握一个Python库--datetime库 **datatime** 模块题共用一些处理日期,时间和时间间隔的函数.这个模块使用面向对象的交互取代了**time**模块中整形/元组类型的时间函 ...

  6. python编一个答题程序_我开发了一个Python答题小程序,近70份奖品等你来拿

    微信小程序非常火爆,我想做小程序已经很久了,几个月前终于下定决心做一款小程序.本身是码农出身,希望做一款跟编程相关的小程序,于是就有了这一款"码题达人"小程序. 搜索微信小程序:码 ...

  7. pyhton如何导入包的每一个文件_如何开始第一个 Python 编程实践项目?

    首发公众号:交通攻城狮 微信ID:TrafficBlog 2020,第 15 期 导语:上期我们谈了谈如何高效的入门 Python 编程,了解了 Python 的编程环境以及常用的包,如 Pandas ...

  8. python怎么开始编程_如何开始第一个 Python 编程实践项目?

    导语:上期我们谈了谈如何高效的入门 Python 编程,了解了 Python 的编程环境以及常用的包,如 Pandas.Matplotlib.Numpy 等.这次我们将以实践项目的形式,帮助大家快速的 ...

  9. python 两点曲线_十行代码,用Python做一个迷你版的美图秀秀

    美图秀秀相信大家都不陌生,大家只要操作美图秀秀,就可以P掉图片中脸上的一些瑕疵,让人变得更加的美丽.今天小编就带领大家来借助Python和Flask来实现一个美图秀秀的网页设计,大家只需要通过网页上传 ...

最新文章

  1. 本科生新算法打败NeRF,不用神经网络照片也能动起来,提速100倍
  2. 6.28 头像预览:form方法和ajax方法
  3. WCF duplex service + silverlight 聊天代码
  4. top与bottom、left与right的优先级
  5. json_encode 处理中文乱码
  6. python django用户登录系统_Django实现用户注册登录
  7. linux内核bios,BIOS的启动原理——Linux内核设计学习笔记
  8. 如何搭建个人独立博客
  9. arcgis sample代码之SOE示例代码PageLayout REST Server Object Extension 的源码分析
  10. 【H5调用iOS原生高德定位】
  11. 如何画OFDM频谱图
  12. java求两数最小公倍数_java求解2个数的最小公倍数
  13. akka-typed(10) - event-sourcing, CQRS实战
  14. Linux查看gzip文件原始大小,Linux 文件管理:Linux gzip 压缩
  15. 抖音V1.7.9调研报告
  16. GTD软件比较和选用
  17. 微软今中止撑持XP体系 后XP年代带来多少商机
  18. Window7和Ubuntu双系统 删除Ubuntu
  19. 机械学习十大经典算法
  20. kafka 消费者的消费策略以及再平衡

热门文章

  1. (算法)宝石升级问题
  2. Python语言学习笔记
  3. Linux常用命令 -- screen
  4. Android开发记录(转)
  5. CVS 客户端使用手册
  6. 2.3.2. 进程互斥的软件实现方法
  7. 爬取Github Web API 并存入Mysql数据库
  8. 牛客21781 牛兄牛弟
  9. Hadoop相关技术
  10. hbase单机模式配置