您的位置:时时app平台注册网站 > 编程知识 > 我的第一个python web开发框架(33)——接口代码

我的第一个python web开发框架(33)——接口代码

2019-12-06 10:46

时时app平台注册网站 1时时app平台注册网站 2

  日常的话,我们在付出时开采ORM未有团结想要的章程时,我们须要做以下考虑:

 

  大家能够将它拆分成get_model_sql()和get_model(卡塔尔多少个措施,一个拍卖sql组合,一个实践获取结果,前边四个能够给业务调用,后面一个直接给相应的顺序调用

 1     ##############################################################
 2     ### 更新用户信息到数据库 ###
 3     ##############################################################
 4     # 更新当前管理员最后登录时间、Ip与登录次数(字段说明,请看数据字典)
 5     fields = {
 6         'last_login_time': 'now()',
 7         'last_login_ip': string(ip),
 8         'login_count': 'login_count 1',
 9     }
10     # 写入数据库
11     _manager_logic.edit_model(manager_id, fields)

 

View Code

  上边改变调用例子(请查看login.py第35行相近)

  针对地点这一个读取付加物记录实体的功能,大家像上生龙活虎章同样,先创立好叁个付加物管理的逻辑类,世袭ORM基类

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 from common import db_helper, cache_helper, encrypt_helper
  5 
  6 
  7 class LogicBase():
  8     """逻辑层基础类"""
  9 
 10     def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):
 11         """类初始化"""
 12         # 数据库参数
 13         self.__db = db
 14         # 是否输出执行的Sql语句到日志中
 15         self.__is_output_sql = is_output_sql
 16         # 表名称
 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     def get_model_sql(self, wheres):
 28         """通过条件获取一条记录"""
 29         # 如果有条件,则自动添加where
 30         if wheres:
 31             wheres = ' where '   wheres
 32 
 33         # 合成sql语句
 34         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % 
 35               {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
 36         return sql
 37 
 38     def get_model_for_pk_sql(self, pk, wheres=''):
 39         """通过主键值获取数据库记录实体"""
 40         # 组装查询条件
 41         wheres = '%s = %s' % (self.__pk_name, str(pk))
 42         return self.get_model_sql(wheres)
 43 
 44     def get_value_sql(self, column_name, wheres=''):
 45         """
 46         获取指定条件的字段值————多于条记录时,只取第一条记录
 47         :param column_name: 单个字段名,如:id
 48         :param wheres: 查询条件
 49         :return: 7 (指定的字段值)
 50         """
 51         if wheres:
 52             wheres = ' where '   wheres
 53 
 54         sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' % 
 55               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
 56         return sql
 57 
 58     def get_value_list_sql(self, column_name, wheres=''):
 59         """
 60         获取指定条件记录的字段值列表
 61         :param column_name: 单个字段名,如:id
 62         :param wheres: 查询条件
 63         :return: [1,3,4,6,7]
 64         """
 65         if not column_name:
 66             column_name = self.__pk_name
 67         elif wheres:
 68             wheres = ' where '   wheres
 69 
 70         sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' % 
 71               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
 72         return sql
 73 
 74     def add_model_sql(self, fields, returning=''):
 75         """新增数据库记录"""
 76         ### 拼接sql语句 ###
 77         # 初始化变量
 78         key_list = []
 79         value_list = []
 80         # 将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组
 81         # PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串
 82         # 比如:
 83         #   传入的字典为: {'id': 1, 'name': '名称'}
 84         #   那么生成的key_list为:'id','name'
 85         #   而value_list为:'%(id)s,%(name)s'
 86         #   最终而value_list为字符串对应名称位置会被替换成相应的值
 87         for key in fields.keys():
 88             key_list.append(key)
 89             value_list.append('%('   key   ')s')
 90         # 设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串
 91         parameter = {
 92             'table_name': self.__table_name,
 93             'pk_name': self.__pk_name,
 94             'key_list': ','.join(key_list),
 95             'value_list': ','.join(value_list)
 96         }
 97         # 如果有指定返回参数,则添加
 98         if returning:
 99             parameter['returning'] = ', '   returning
100         else:
101             parameter['returning'] = ''
102 
103         # 生成可以使用字典替换的字符串
104         sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" % parameter
105         # 将生成好的字符串替字典参数值,生成最终可执行的sql语句
106         return sql % fields
107 
108     def edit_sql(self, fields, wheres='', returning=''):
109         """
110         批量编辑数据库记录
111         :param fields: 要更新的字段(字段名与值存储在字典中)
112         :param wheres: 更新条件
113         :param returning: 更新成功后,返回的字段名
114         :param is_update_cache: 是否同步更新缓存
115         :return:
116         """
117         ### 拼接sql语句 ###
118         # 拼接字段与值
119         field_list = [key   ' = %('   key   ')s' for key in fields.keys()]
120         # 设置sql拼接字典
121         parameter = {
122             'table_name': self.__table_name,
123             'pk_name': self.__pk_name,
124             'field_list': ','.join(field_list)
125         }
126         # 如果存在更新条件,则将条件添加到sql拼接更换字典中
127         if wheres:
128             parameter['wheres'] = ' where '   wheres
129         else:
130             parameter['wheres'] = ''
131 
132         # 如果有指定返回参数,则添加
133         if returning:
134             parameter['returning'] = ', '   returning
135         else:
136             parameter['returning'] = ''
137 
138         # 生成sql语句
139         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
140         return sql % fields
141 
142     def edit_model_sql(self, pk, fields, wheres='', returning=''):
143         """编辑单条数据库记录"""
144         if wheres:
145             wheres = self.__pk_name   ' = '   str(pk)   ' and '   wheres
146         else:
147             wheres = self.__pk_name   ' = '   str(pk)
148 
149         return self.edit_sql(fields, wheres, returning)
150 
151     def delete_sql(self, wheres='', returning=''):
152         """
153         批量删除数据库记录
154         :param wheres: 删除条件
155         :param returning: 删除成功后,返回的字段名
156         :param is_update_cache: 是否同步更新缓存
157         :return:
158         """
159         # 如果存在条件
160         if wheres:
161             wheres = ' where '   wheres
162 
163         # 如果有指定返回参数,则添加
164         if returning:
165             returning = ', '   returning
166 
167         # 生成sql语句
168         sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % 
169               {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
170         return sql
171 
172     def delete_model_sql(self, pk, wheres='', returning=''):
173         """删除单条数据库记录"""
174         if wheres:
175             wheres = self.__pk_name   ' = '   str(pk)   ' and '   wheres
176         else:
177             wheres = self.__pk_name   ' = '   str(pk)
178 
179         return self.delete_sql(wheres, returning)
180 
181     def get_list_sql(self, column_name_list='', wheres='', orderby=None, table_name=None):
182         """
183         获取指定条件的数据库记录集
184         :param column_name_list:      查询字段
185         :param wheres:      查询条件
186         :param orderby:     排序规则
187         :param table_name:     查询数据表,多表查询时需要设置
188         :return:
189         """
190         # 初始化查询数据表名称
191         if not table_name:
192             table_name = self.__table_name
193         # 初始化查询字段名
194         if not column_name_list:
195             column_name_list = self.__column_name_list
196         # 初始化查询条件
197         if wheres:
198             # 如果是字符串,表示该查询条件已组装好了,直接可以使用
199             if isinstance(wheres, str):
200                 wheres = 'where '   wheres
201             # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
202             elif isinstance(wheres, list):
203                 wheres = 'where '   ' and '.join(wheres)
204         # 初始化排序
205         if not orderby:
206             orderby = self.__pk_name   ' desc'
207         #############################################################
208 
209         ### 按条件查询数据库记录
210         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s " % 
211               {'column_name_list': column_name_list,
212                'table_name': table_name,
213                'wheres': wheres,
214                'orderby': orderby}
215         return sql
216 
217     def get_count_sql(self, wheres=''):
218         """获取指定条件记录数量"""
219         if wheres:
220             wheres = ' where '   wheres
221         sql = 'select count(1) as total from %(table_name)s %(wheres)s ' % 
222               {'table_name': self.__table_name, 'wheres': wheres}
223         return sql
224 
225     def get_sum_sql(self, fields, wheres):
226         """获取指定条件记录数量"""
227         sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s ' % 
228               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
229         return sql
230 
231     def get_min_sql(self, fields, wheres):
232         """获取该列记录最小值"""
233         sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s ' % 
234               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
235         return sql
236 
237     def get_max_sql(self, fields, wheres):
238         """获取该列记录最大值"""
239         sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s ' % 
240               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
241         return sql
242 
243     #####################################################################
244 
245 
246     #####################################################################
247     ### 执行Sql ###
248 
249     def select(self, sql):
250         """执行sql查询语句(select)"""
251         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
252             # 执行sql语句
253             result = db.execute(sql)
254             if not result:
255                 result = []
256         return result
257 
258     def execute(self, sql):
259         """执行sql语句,并提交事务"""
260         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
261             # 执行sql语句
262             result = db.execute(sql)
263             if result:
264                 db.commit()
265             else:
266                 result = []
267         return result
268 
269     def copy(self, values, columns):
270         """批量更新数据"""
271         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
272             # 执行sql语句
273             result = db.copy(values, self.__table_name, columns)
274         return result
275 
276     def get_model(self, wheres):
277         """通过条件获取一条记录"""
278         # 生成sql
279         sql = self.get_model_sql(wheres)
280         # 执行查询操作
281         result = self.select(sql)
282         if result:
283             return result[0]
284         return {}
285 
286     def get_model_for_pk(self, pk, wheres=''):
287         """通过主键值获取数据库记录实体"""
288         if not pk:
289             return {}
290         # 生成sql
291         sql = self.get_model_for_pk_sql(pk, wheres)
292         # 执行查询操作
293         result = self.select(sql)
294         if result:
295             return result[0]
296         return {}
297 
298     def get_value(self, column_name, wheres=''):
299         """
300         获取指定条件的字段值————多于条记录时,只取第一条记录
301         :param column_name: 单个字段名,如:id
302         :param wheres: 查询条件
303         :return: 7 (指定的字段值)
304         """
305         if not column_name:
306             return None
307 
308         # 生成sql
309         sql = self.get_value_sql(column_name, wheres)
310         result = self.select(sql)
311         # 如果查询成功,则直接返回记录字典
312         if result:
313             return result[0].get(column_name)
314 
315     def get_value_list(self, column_name, wheres=''):
316         """
317         获取指定条件记录的字段值列表
318         :param column_name: 单个字段名,如:id
319         :param wheres: 查询条件
320         :return: [1,3,4,6,7]
321         """
322         # 生成sql
323         sql = self.get_value_list_sql(column_name, wheres)
324         result = self.select(sql)
325         # 如果查询失败或不存在指定条件记录,则直接返回初始值
326         if result and isinstance(result, list):
327             return result[0].get('list')
328         else:
329             return []
330 
331     def add_model(self, fields, returning=''):
332         """新增数据库记录"""
333         # 生成sql
334         sql = self.add_model_sql(fields, returning)
335         result = self.execute(sql)
336         if result:
337             return result[0]
338         return {}
339 
340     def edit(self, fields, wheres='', returning='', is_update_cache=True):
341         """
342         批量编辑数据库记录
343         :param fields: 要更新的字段(字段名与值存储在字典中)
344         :param wheres: 更新条件
345         :param returning: 更新成功后,返回的字段名
346         :param is_update_cache: 是否同步更新缓存
347         :return:
348         """
349         # 生成sql
350         sql = self.edit_sql(fields, wheres, returning)
351         result = self.execute(sql)
352         if result:
353             # 判断是否删除对应的缓存
354             if is_update_cache:
355                 # 循环删除更新成功的所有记录对应的缓存
356                 for model in result:
357                     self.del_model_for_cache(model.get(self.__pk_name, 0))
358                 # 同步删除与本表关联的缓存
359                 self.del_relevance_cache()
360         return result
361 
362     def edit_model(self, pk, fields, wheres='', returning='', is_update_cache=True):
363         """编辑单条数据库记录"""
364         if not pk:
365             return {}
366         # 生成sql
367         sql = self.edit_model_sql(pk, fields, wheres, returning)
368         result = self.execute(sql)
369         if result:
370             # 判断是否删除对应的缓存
371             if is_update_cache:
372                 # 删除更新成功的所有记录对应的缓存
373                 self.del_model_for_cache(result[0].get(self.__pk_name, 0))
374                 # 同步删除与本表关联的缓存
375                 self.del_relevance_cache()
376         return result
377 
378     def delete(self, wheres='', returning='', is_update_cache=True):
379         """
380         批量删除数据库记录
381         :param wheres: 删除条件
382         :param returning: 删除成功后,返回的字段名
383         :param is_update_cache: 是否同步更新缓存
384         :return:
385         """
386         # 生成sql
387         sql = self.delete_sql(wheres, returning)
388         result = self.execute(sql)
389         if result:
390             # 同步删除对应的缓存
391             if is_update_cache:
392                 for model in result:
393                     self.del_model_for_cache(model.get(self.__pk_name, 0))
394                 # 同步删除与本表关联的缓存
395                 self.del_relevance_cache()
396         return result
397 
398     def delete_model(self, pk, wheres='', returning='', is_update_cache=True):
399         """删除单条数据库记录"""
400         if not pk:
401             return {}
402         # 生成sql
403         sql = self.delete_model_sql(pk, wheres, returning)
404         result = self.execute(sql)
405         if result:
406             # 同步删除对应的缓存
407             if is_update_cache:
408                 self.del_model_for_cache(result[0].get(self.__pk_name, 0))
409                 # 同步删除与本表关联的缓存
410                 self.del_relevance_cache()
411         return result
412 
413     def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):
414         """
415         获取指定条件的数据库记录集
416         :param column_name_list:      查询字段
417         :param wheres:      查询条件
418         :param page_number:   分页索引值
419         :param page_size:    分页大小, 存在值时才会执行分页
420         :param orderby:     排序规则
421         :param table_name:     查询数据表,多表查询时需要设置
422         :return: 返回记录集总数量与分页记录集
423             {'records': 0, 'total': 0, 'page': 0, 'rows': []}
424         """
425         # 初始化输出参数:总记录数量与列表集
426         data = {
427             'records': 0,  # 总记录数
428             'total': 0,  # 总页数
429             'page': 1,  # 当前页面索引
430             'rows': [],  # 查询结果(记录列表)
431         }
432         # 初始化查询数据表名称
433         if not table_name:
434             table_name = self.__table_name
435         # 初始化查询字段名
436         if not column_name_list:
437             column_name_list = self.__column_name_list
438         # 初始化查询条件
439         if wheres:
440             # 如果是字符串,表示该查询条件已组装好了,直接可以使用
441             if isinstance(wheres, str):
442                 wheres = 'where '   wheres
443             # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
444             elif isinstance(wheres, list):
445                 wheres = 'where '   ' and '.join(wheres)
446         # 初始化排序
447         if not orderby:
448             orderby = self.__pk_name   ' desc'
449         # 初始化分页查询的记录区间
450         paging = ''
451 
452         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
453             #############################################################
454             # 判断是否需要进行分页
455             if not page_size is None:
456                 ### 执行sql,获取指定条件的记录总数量
457                 sql = 'select count(1) as records from %(table_name)s %(wheres)s ' % 
458                       {'table_name': table_name, 'wheres': wheres}
459                 result = db.execute(sql)
460                 # 如果查询失败或不存在指定条件记录,则直接返回初始值
461                 if not result or result[0]['records'] == 0:
462                     return data
463 
464                 # 设置记录总数量
465                 data['records'] = result[0].get('records')
466 
467                 #########################################################
468                 ### 设置分页索引与页面大小 ###
469                 if page_size <= 0:
470                     page_size = 10
471                 # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
472                 if data['records'] % page_size == 0:
473                     page_total = data['records'] // page_size
474                 else:
475                     page_total = data['records'] // page_size   1
476                 # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
477                 if page_number < 1 or page_number > page_total:
478                     page_number = page_total
479                 # 记录总页面数量
480                 data['total'] = page_total
481                 # 记录当前页面值
482                 data['page'] = page_number
483                 # 计算当前页面要显示的记录起始位置(limit指定的位置)
484                 record_number = (page_number - 1) * page_size
485                 # 设置查询分页条件
486                 paging = ' limit '   str(page_size)   ' offset '   str(record_number)
487             #############################################################
488 
489             ### 按条件查询数据库记录
490             sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % 
491                   {'column_name_list': column_name_list,
492                    'table_name': table_name,
493                    'wheres': wheres,
494                    'orderby': orderby,
495                    'paging': paging}
496             result = db.execute(sql)
497             if result:
498                 data['rows'] = result
499                 # 不需要分页查询时,直接在这里设置总记录数
500                 if page_size is None:
501                     data['records'] = len(result)
502 
503         return data
504 
505     def get_count(self, wheres=''):
506         """获取指定条件记录数量"""
507         # 生成sql
508         sql = self.get_count_sql(wheres)
509         result = self.select(sql)
510         # 如果查询存在记录,则返回true
511         if result:
512             return result[0].get('total')
513         return 0
514 
515     def get_sum(self, fields, wheres):
516         """获取指定条件记录数量"""
517         # 生成sql
518         sql = self.get_sum_sql(fields, wheres)
519         result = self.select(sql)
520         # 如果查询存在记录,则返回true
521         if result and result[0].get('total'):
522             return result[0].get('total')
523         return 0
524 
525     def get_min(self, fields, wheres):
526         """获取该列记录最小值"""
527         # 生成sql
528         sql = self.get_min_sql(fields, wheres)
529         result = self.select(sql)
530         # 如果查询存在记录,则返回true
531         if result and result[0].get('min'):
532             return result[0].get('min')
533 
534     def get_max(self, fields, wheres):
535         """获取该列记录最大值"""
536         # 生成sql
537         sql = self.get_max_sql(fields, wheres)
538         result = self.select(sql)
539         # 如果查询存在记录,则返回true
540         if result and result[0].get('max'):
541             return result[0].get('max')
542 
543     #####################################################################
544 
545 
546     #####################################################################
547     ### 缓存操作方法 ###
548 
549     def get_cache_key(self, pk):
550         """获取缓存key值"""
551         return ''.join((self.__table_name, '_', str(pk)))
552 
553     def set_model_for_cache(self, pk, value, time=43200):
554         """更新存储在缓存中的数据库记录,缓存过期时间为12小时"""
555         # 生成缓存key
556         key = self.get_cache_key(pk)
557         # 存储到nosql缓存中
558         cache_helper.set(key, value, time)
559 
560     def get_model_for_cache(self, pk):
561         """从缓存中读取数据库记录"""
562         # 生成缓存key
563         key = self.get_cache_key(pk)
564         # 从缓存中读取数据库记录
565         result = cache_helper.get(key)
566         # 缓存中不存在记录,则从数据库获取
567         if not result:
568             result = self.get_model_for_pk(pk)
569             self.set_model_for_cache(pk, result)
570         if result:
571             return result
572         else:
573             return {}
574 
575     def get_model_for_cache_of_where(self, where):
576         """
577         通过条件获取记录实体(我们经常需要使用key、编码或指定条件来获取记录,这时可以通过当前方法来获取)
578         :param where: 查询条件
579         :return: 记录实体
580         """
581         # 生成实体缓存key
582         model_cache_key = self.__table_name   encrypt_helper.md5(where)
583         # 通过条件从缓存中获取记录id
584         pk = cache_helper.get(model_cache_key)
585         # 如果主键id存在,则直接从缓存中读取记录
586         if pk:
587             return self.get_model_for_cache(pk)
588 
589         # 否则从数据库中获取
590         result = self.get_model(where)
591         if result:
592             # 存储条件对应的主键id值到缓存中
593             cache_helper.set(model_cache_key, result.get(self.__pk_name))
594             # 存储记录实体到缓存中
595             self.set_model_for_cache(result.get(self.__pk_name), result)
596             return result
597 
598     def get_value_for_cache(self, pk, column_name):
599         """获取指定记录的字段值"""
600         return self.get_model_for_cache(pk).get(column_name)
601 
602     def del_model_for_cache(self, pk):
603         """删除缓存中指定数据"""
604         # 生成缓存key
605         key = self.get_cache_key(pk)
606         # log_helper.info(key)
607         # 存储到nosql缓存中
608         cache_helper.delete(key)
609 
610     def add_relevance_cache_in_list(self, key):
611         """将缓存名称存储到列表里————主要存储与记录变更关联的"""
612         # 从nosql中读取全局缓存列表
613         cache_list = cache_helper.get(self.__cache_list)
614         # 判断缓存列表是否有值,有则进行添加操作
615         if cache_list:
616             # 判断是否已存储列表中,不存在则执行添加操作
617             if not key in cache_list:
618                 cache_list.append(key)
619                 cache_helper.set(self.__cache_list, cache_list)
620         # 无则直接创建全局缓存列表,并存储到nosql中
621         else:
622             cache_list = [key]
623             cache_helper.set(self.__cache_list, cache_list)
624 
625     def del_relevance_cache(self):
626         """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""
627         # 从nosql中读取全局缓存列表
628         cache_list = cache_helper.get(self.__cache_list)
629         # 清除已删除缓存列表
630         cache_helper.delete(self.__cache_list)
631         if cache_list:
632             # 执行删除操作
633             for cache in cache_list:
634                 cache_helper.delete(cache)
635 
636     #####################################################################

  这段代码后半片段能够参照他事他说加以考查付加物的删减接口完结,前半有个别要求调用付加物艺术开展决断管理。

@get('/api/product/<id:int>/')
def callback(id):
    """
    获取指定记录
    """
    # 实例化product表操作类ProductLogic
    _product_logic = product_logic.ProductLogic()
    # 执行get_model_for_pk()方法,获取记录实体
    model = _product_logic.get_model_for_pk(id)
    if model:
        return web_helper.return_msg(0, '查询成功', model)
    else:
        return web_helper.return_msg(-1, "查询失败")

  那么相应怎么贯彻吗?大家都理解要协理专门的学业,就一定要让分裂的sql语句在同二个业务中举行,也便是说,大家须求在叁个with中实施全部的sql语句,退步则回滚,成功再交由业务。

  在编排时大家会发觉,我们的ORM并不曾直接判别记录是不是存在的主意,独有三个用以获取钦定条件记录数的秘籍。

  在组成sql前,我们供给选对查询条件进行组装,这里大家一贯动用self.__pk_name,在上意气风发章伊始化时定义好的暗许项,在那不直接动用id做为条件字段,是为着当现身主键名字为其余字符时,能够灵活管理。比方订单表使用code为主键时,就能够直接绑定code并非自增id了。譬喻self.__pk_name开始值是id,主键pk值是1,那么组装后的询问条件为 id=1

  本文对应的源码下载(一些接口进行了重构,有个别还没拍卖,所以源码也许一贯运转不了,下大器晚成章节会讲到全体代码应用ORM模块重构内容)

  正文对应的源码下载

  和前面包车型地铁代码相比较,代码看起来大概多了

 

 1 @delete('/api/product/<id:int>/')
 2 def callback(id):
 3     """
 4     删除指定记录
 5     """
 6     # 实例化product表操作类ProductLogic
 7     _product_logic = product_logic.ProductLogic()
 8     result = _product_logic.delete_model(id)
 9     # 判断是否提交成功
10     if result:
11         return web_helper.return_msg(0, '成功')
12     else:
13         return web_helper.return_msg(-1, "删除失败")

 

 1     def get_model_sql(self, wheres):
 2         """通过条件获取一条记录"""
 3         # 如果有条件,则自动添加where
 4         if wheres:
 5             wheres = ' where '   wheres
 6 
 7         # 合成sql语句
 8         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % 
 9               {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
10         return sql
11 
12     def get_model(self, wheres):
13         """通过条件获取一条记录"""
14         # 生成sql
15         sql = self.get_model_sql(wheres)
16         # 初化化数据库链接
17         result = self.select(sql)
18         if result:
19             return result[0]
20         return {}
 1 @delete('/api/product/<id:int>/')
 2 def callback(id):
 3     """
 4     删除指定记录
 5     """
 6     # 编辑记录
 7     sql = """delete from product where id=%s returning id"""
 8     vars = (id,)
 9     # 写入数据库
10     result = db_helper.write(sql, vars)
11     # 判断是否提交成功
12     if result:
13         return web_helper.return_msg(0, '成功')
14     else:
15         return web_helper.return_msg(-1, "删除失败")

  首先咱们来拜会在此以前项目中,最遍布的获取钦定主键的笔录实体

 

 

  在发轫在此之前,我们再持续构思一下,大家赢得记录实体,通过主键查询只是累累艺术中的个中二个,大家还有或许会时有时应用种种规范的三结合来开展查询,读取记录实体,所以那边大家得以兑现自定义准则查询的方法

 

  付加物分类有关接口(product_class.py)与制品有关接口(product.py)效能大致,具体落实自身就不后生可畏生机勃勃批注了,大家能够慈详试试

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

from logic import _logic_base
from config import db_config


class ProductLogic(_logic_base.LogicBase):
    """产品管理表逻辑类"""

    def __init__(self):
        # 表名称
        __table_name = 'product'
        # 初始化
        _logic_base.LogicBase.__init__(self, db_config.DB, db_config.IS_OUTPUT_SQL, __table_name)

  代码改动起来异常的粗略,举例说获取记录格局

1     ##############################################################
2     ### 获取登录用户记录,并进行登录验证 ###
3     ##############################################################
4     sql = """select * from manager where login_name='%s'""" % (username,)
5     # 从数据库中读取用户信息
6     manager_result = db_helper.read(sql)
7     # 判断用户记录是否存在
8     if not manager_result:
9         return web_helper.return_msg(-1, '账户不存在')

  在接纳到主健值以后,大家供给对它实行简易的论断管理,假如它为空则直接重返空字典。

  从全体代码能够观望,重构后的类多了多数sql生成方法,它们其实是从原方法中享用出sql合成代码,将它们独立出来而已。

  倘使字段是数值型,要让它实行总括,直接像上面那样写也行,能够是四个字段用加号连起来。当然你也可以将字段时读出来举办测算后再赋值提交也绝非难题

    def get_model_for_pk(self, pk):
        """通过主键值获取数据库记录实体"""
        if not pk:
            return {}
        # 组装查询条件
        wheres = '%s = %s' % (self.__pk_name, str(pk))
        # 合成sql语句
        sql = "select %(column_name_list)s from %(table_name)s where %(wheres)s" % 
              {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
        # 初化化数据库链接
        with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
            # 执行sql语句
            _result = db.execute(sql)
            # 对返回的内容进行处理
            if _result:
                result = _result[0]
            else:
                result = {}
        return result

  别的代码不生机勃勃意气风发细述,大家温馨看注重构后的结果

 

  输出结果:

  用心的爱人大概会意识,在事务管理中,进行编辑操作之后,会执行缓存的扫除操作,那是因为大家在ORM中所绑定的缓存自动肃清操作,是在对应的举办办法中,并不是sql生成方法里,所以在开展事务时,借使您选用了缓存的形式,在这间就要求手动加多息灭缓存操作,不然就能产生脏数据。

  假若是数值类型,间接写值就足以了,当然一向赋字符串值也绝非关联,因为生成sql是不会自行抬高单撇号的

    def get_model_for_pk(self, pk, wheres=''):
        """通过主键值获取数据库记录实体"""
        if not pk:
            return {}
        # 组装查询条件
        wheres = '%s = %s' % (self.__pk_name, str(pk))

        return self.get_model(wheres)

python开拓QQ群:669058475    作者博客:

  假设要赋postgresql系统变量,如now(卡塔尔(英语:State of Qatar),直接像上面那样写就可以了

python开垦QQ群:669058475    小编博客:

 

  我们得以退换为:

版权注明:本文原创发表于 博客园,作者为 AllEmpty 正文招待转发,但未经作者同意必得保留此段评释,且在篇章页面显然地点给出最早的文章连接,不然便是侵犯权益。

  由于大家的逻辑层种种类都以三回九转ORM基类来贯彻的,而职业的开关放在各类类中就不对劲,只怕会设有毛病,所以在履行事务时,直接调用db_helper模块,使用with开始化好数据库链接,然后在点子里编写并实行种种sql语句。

 1     def get_model_for_cache_of_where(self, where):
 2         """
 3         通过条件获取记录实体————条件必须是额外的主键,也就是说记录是唯一的(我们经常需要使用key、编码或指定条件来获取记录,这时可以通过当前方法来获取)
 4         :param where: 查询条件
 5         :return: 记录实体
 6         """
 7         # 生成实体缓存key
 8         model_cache_key = self.__table_name   encrypt_helper.md5(where)
 9         # 通过条件从缓存中获取记录id
10         pk = cache_helper.get(model_cache_key)
11         # 如果主键id存在,则直接从缓存中读取记录
12         if pk:
13             return self.get_model_for_cache(pk)
14 
15         # 否则从数据库中获取
16         result = self.get_model(where)
17         if result:
18             # 存储条件对应的主键id值到缓存中
19             cache_helper.set(model_cache_key, result.get(self.__pk_name))
20             # 存储记录实体到缓存中
21             self.set_model_for_cache(result.get(self.__pk_name), result)
22             return result

  大家就可以直接改换前边的接口调用代码了

 1 #!/usr/bin/evn python
 2 # coding=utf-8
 3 
 4 import unittest
 5 from common import db_helper
 6 from common.string_helper import string
 7 from config import db_config
 8 from logic import product_logic, product_class_logic
 9 
10 
11 class DbHelperTest(unittest.TestCase):
12     """数据库操作包测试类"""
13 
14     def setUp(self):
15         """初始化测试环境"""
16         print('------ini------')
17 
18     def tearDown(self):
19         """清理测试环境"""
20         print('------clear------')
21 
22     def test(self):
23         ##############################################
24         # 只需要看这里,其他代码是测试用例的模板代码 #
25         ##############################################
26         # 测试事务
27         # 使用with方法,初始化数据库链接
28         with db_helper.PgHelper(db_config.DB, db_config.IS_OUTPUT_SQL) as db:
29             # 实例化product表操作类ProductLogic
30             _product_logic = product_logic.ProductLogic()
31             # 实例化product_class表操作类product_class_logic
32             _product_class_logic = product_class_logic.ProductClassLogic()
33             # 初始化产品分类主键id
34             id = 1
35 
36             # 获取产品分类信息(为了查看效果,所以加了这段获取分类信息)
37             sql = _product_class_logic.get_model_for_pk_sql(id)
38             print(sql)
39             # 执行sql语句
40             result = db.execute(sql)
41             if not result:
42                 print('不存在指定的产品分类')
43                 return
44             print('----产品分类实体----')
45             print(result)
46             print('-------------------')
47 
48             # 禁用产品分类
49             fields = {
50                 'is_enable': 0
51             }
52             sql = _product_class_logic.edit_model_sql(id, fields, returning='is_enable')
53             print(sql)
54             # 执行sql语句
55             result = db.execute(sql)
56             if not result:
57                 # 执行失败,执行回滚操作
58                 db.rollback()
59                 print('禁用产品分类失败')
60                 return
61             # 执行缓存清除操作
62             _product_class_logic.del_model_for_cache(id)
63             _product_class_logic.del_relevance_cache()
64             print('----执行成功后的产品分类实体----')
65             print(result)
66             print('-------------------------------')
67 
68             # 同步禁用产品分类对应的所有产品
69             sql = _product_logic.edit_sql(fields, 'product_class_id='   str(id), returning='is_enable')
70             print(sql)
71             # 执行sql语句
72             result = db.execute(sql)
73             if not result:
74                 # 执行失败,执行回滚操作
75                 db.rollback()
76                 print('同步禁用产品分类对应的所有产品失败')
77                 return
78             # 执行缓存清除操作
79             for model in result:
80                 _product_class_logic.del_model_for_cache(model.get('id'))
81             _product_class_logic.del_relevance_cache()
82             print('----执行成功后的产品实体----')
83             print(result)
84             print('---------------------------')
85 
86             db.commit()
87             print('执行成功')
88         ##############################################
89 
90 if __name__ == '__main__':
91     unittest.main()

  我们在开拓时,除了通过主键id来博取记录实体以外,在某些数据表中,还有或然会设有第4个主键,或四个主键的景况,大家须要经过那些主键来拿到相应的记录实休,比如说助理馆员或客户表中的登录账号字段;订单表中的订单编码字段等。

 

 

  具体操作需求我们自身多debug,多测验使用才精通怎么采用到实际项目中。

  

版权注解:本文原创发布于 博客园,作者为 AllEmpty 正文迎接转发,但未经作者同意必得保留此段评释,且在篇章页面鲜明地方给出原版的书文连接,否则正是侵害版权。

python开采QQ群:669058475    作者博客:

 

  接下去大家编辑单元测量检验代码,推行一下事务看看效果

  大家能够更换为:

  为了让这些读取记录实体的效应能运用的更加的广泛,大家还索要对它举办改动与加工。

 

  这段代码的供给是判别钦定的归类是还是不是被成品引用,抽象出来的情致便是决断内定条件的笔录是不是留存,对于那一个成效有付出经历的同伙非常轻松看清它是众多地点都有异常的大只怕要用到的通用方法,所以大家必要在ORM中加进一下以此办法。而大家ORM已经存在get_count(卡塔尔这些获得记录数的秘技存在了,大家能够通过调用那一个法子来决断记录数据是还是不是大于0,来得出钦定条件的记录是不是留存这么的结果。

  代码看起来与前面包车型大巴get_model_for_pk(卡塔尔(英语:State of Qatar)方法许多,只然而将pk参数改为准则参数wheres,无需再组成主键查询条件而已。由于几个函数部分代码相通,所以大家需求对get_model_for_pk(卡塔尔国方法开展重构,间接将创设好的查询条件提交给get_model(卡塔尔方法来举行就足以了,将它回到的情节一贯再次回到给主程序。

  施行结果:

  首先是初步化付加物逻辑层操作类,然后调用delete_model(卡塔尔这些艺术就足以了

  改造完毕后,使用前边的单元测验跑一下,能够看出重临结果生龙活虎致。扩展了get_model(卡塔尔方法之后,大家就足以灵活的自定义自便的查询条件来读取记录了。这里要注意的是,使用get_model(卡塔尔方法查询时,有望在查询时会重返多条记下,这些格局它只回去第一条记下。须要再次来到多条记下时,能够应用大家一而再再三再四封装的别的ORM方法。

  写到这里,基本的ORM功用就完毕了,不知大家有没有觉察,这些ORM每一种方法都是在with中实行的,也正是说每一种方法都是多个全部的政工,当它施行到位以往也会将工作提交,那么只要大家想要进行贰个复杂的事务时,它并一定要负众望,所以大家还需求对它举行退换,让它援助sql事务。

  借使前方代码有认真读书的伴儿见到这段代码,要改成ORM方式应该相当轻易达成了

------ini------
{'product_class_id': 1, 'place_of_origin': '广东广州', 'name': '饼干', 'id': 2, 'standard': '500g', 'is_enable': 1, 'add_time': datetime.datetime(2018, 7, 25, 23, 10, 4), 'quality_guarantee_period': '2018年12月', 'code': '20180212321211', 'content': '产品描述', 'front_cover_img': 'http://xxx.com/xxx.jpg'}
------clear------
 1 ------ini------
 2 select * from product_class  where id = 1
 3 ----产品分类实体----
 4 [{'add_time': datetime.datetime(2018, 8, 17, 16, 14, 54), 'id': 1, 'is_enable': 1, 'name': '饼干'}]
 5 -------------------
 6 update product_class set is_enable = 0  where id = 1 returning id , is_enable
 7 ----执行成功后的产品分类实体----
 8 [{'id': 1, 'is_enable': 0}]
 9 -------------------------------
10 update product set is_enable = 0  where product_class_id=1 returning id , is_enable
11 ----执行成功后的产品实体----
12 [{'id': 2, 'is_enable': 0}, {'id': 7, 'is_enable': 0}, {'id': 14, 'is_enable': 0}, {'id': 15, 'is_enable': 0}]
13 ---------------------------
14 执行成功
15 ------clear------

  符合规律情形下,我们直接通过get_model(卡塔尔国方法就足以读取对应的笔录了,纵然大家想减弱数据库的询问,直接在缓存中哪些选用呢?直接存取记录实体,由于那个额外的主键并未与ORM中的编辑与删除操作关联,即在开展编辑与删除操作时不会同步校订用别样主键存款和储蓄的实体内容,那样就能够时有发生脏数据。所以我们得以换豆蔻年华种思路来兑现,大家能够将那么些额外的主键和呼应的值生成缓存组合key,里面储存对应的记录实体id,也便是说在蕴藏记录实体时,依然使用原本的主键id存储该实体,然后用额外主键和对应值生成缓存组合key中存款和储蓄主键id,在得到记录实体时,先用那些组成key提取对应的id,再用这几个id来博取记录实体。那一个注脚好像有个别绕,我们温馨debug一下就非常轻便驾驭在那之中的规律了,上边看代码:

  正文对应的源码下载 (为了便利我们掌握,源码包只放了这两章所用到的有个别代码)

 1     def get_model(self, wheres):
 2         """通过条件获取一条记录"""
 3         # 如果有条件,则自动添加where
 4         if wheres:
 5             wheres = ' where '   wheres
 6 
 7         # 合成sql语句
 8         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % 
 9               {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
10         # 初化化数据库链接
11         result = self.select(sql)
12         if result:
13             return result[0]
14         return {}

 

  依据那个必要,我们得以相当的轻巧写出这一个措施

  当前逻辑层基类(ORM模块)的sql语句都以在方式中变化(拼接)的,然后在点子的with模块中实施,所以大家必要再行对总体类实行改建,将享有的sql生成方法提炼出来,成为独立的主意,然后在业务中,大家不直接施行获取结果,而是通过ORM生成对应的sql语句,在with中实践那样语句。(当然还会有其余艺术也能贯彻专业,可是在那处不做越来越探幽索隐,因为近期这种是最简易实现职业的情势之大器晚成,多层封装管理,有十分大希望会引致系统变的进一层复杂,代码特别难懂)

 1 @delete('/api/product_class/<id:int>/')
 2 def callback(id):
 3     """
 4     删除指定记录
 5     """
 6     # 实例化product表操作类ProductLogic
 7     _product_logic = product_logic.ProductLogic()
 8     # 判断该分类是否已经被引用,是的话不能直接删除
 9     if _product_logic.exists('product_class_id='   str(id)):
10         return web_helper.return_msg(-1, "该分类已被引用,请清除对该分类的绑定后再来删除")
11 
12     # 实例化product_class表操作类product_class_logic
13     _product_class_logic = product_class_logic.ProductClassLogic()
14     result = _product_class_logic.delete_model(id)
15     # 判断是否提交成功
16     if result:
17         return web_helper.return_msg(0, '成功')
18     else:
19         return web_helper.return_msg(-1, "删除失败")

 

  通过这几个例子,大家在实际上支付进度中,能够灵活的依据自身索要,来扩充或改建对应的后面部分方法,储存你本人的底层框架代码,那么随着开采时间的加码,你付出起各类功能来就能越加一箭穿心了。

  3.sql内需在情势中张开组装

  1.有未有代表能够完结的方法存在

  直接上单元测量检验看看实施功效

 1 @delete('/api/product_class/<id:int>/')
 2 def callback(id):
 3     """
 4     删除指定记录
 5     """
 6     # 判断该分类是否已经被引用,是的话不能直接删除
 7     sql = """select count(*) as total from product where product_class_id=%s""" % (id,)
 8     # 读取记录
 9     result = db_helper.read(sql)
10     if result and result[0].get('total', -1) > 0:
11         return web_helper.return_msg(-1, "该分类已被引用,请清除对该分类的绑定后再来删除")
12 
13     # 编辑记录
14     sql = """delete from product_class where id=%s returning id"""
15     vars = (id,)
16     # 写入数据库
17     result = db_helper.write(sql, vars)
18     # 判断是否提交成功
19     if result:
20         return web_helper.return_msg(0, '成功')
21     else:
22         return web_helper.return_msg(-1, "删除失败")

 

版权评释:本文原创揭橥于 博客园,作者为 AllEmpty 正文招待转发,但未经笔者同意必需保留此段表明,且在篇章页面鲜明地方给出原作连接,不然就是侵犯权益。

  从代码中得以看见,大家需求实践select * from product where id = xx从数据表中查询到大家想要的多寡。

  2.该功能是不是是常用的作用,能还是不能封装成公共艺术,要是能够就将它包裹到逻辑层基类(ORM模块)中去,让具备继续的子类都存有这几个效应

  1.方法名必需是简约易懂的

  前面ORM模块大家早已做到了开支,接下去要做的就是对项目代码实行重构了。因为对底层数据库操作模块(db_helper.py)实行了改动,以前项目标接口代码全都跑不起来了。

    def get_model(self, wheres):
        """通过条件获取一条记录"""
        # 如果有条件,则自动添加where
        if wheres:
            wheres = ' where '   wheres

        # 合成sql语句
        sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % 
              {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
        # 初化化数据库链接
        with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
            # 执行sql语句
            _result = db.execute(sql)
            # 对返回的内容进行处理
            if _result:
                result = _result[0]
            else:
                result = {}
        return result

 

@get('/api/product/<id:int>/')
def callback(id):
    """
    获取指定id的产品记录实体
    """
    sql = """select * from product where id = %s""" % (id,)
    # 读取记录
    result = db_helper.read(sql)
    if result:
        return web_helper.return_msg(0, '成功', result[0])
    else:
        return web_helper.return_msg(-1, "查询失败")

  只必要将第7行到第10行替换对应的调用代码就足以了

  大家通过措施名(get_model_for_pk)应当能够了然,大家是由此主键来拿到钦定的记录实体内容。

  有了那个点子,大家就能够连续对付加物分类删除接口实行改过了

  该方法供给传入的参数值是主键值pk

1     ##############################################################
2     ### 获取登录用户记录,并进行登录验证 ###
3     ##############################################################
4     _manager_logic = manager_logic.ManagerLogic()
5     # 从数据库中读取用户信息
6     manager_result = _manager_logic.get_model_for_cache_of_where('login_name='   string(username))
7     # 判断用户记录是否存在
8     if not manager_result:
9         return web_helper.return_msg(-1, '账户不存在')

  2.主意须求抽取钦命的主键值

1 ##############################################################
2     ### 更新用户信息到数据库 ###
3     ##############################################################
4     # 更新当前管理员最后登录时间、Ip与登录次数(字段说明,请看数据字典)
5     sql = """update manager set last_login_time=%s, last_login_ip=%s, login_count=login_count 1 where id=%s"""
6     # 组合更新值
7     vars = ('now()', ip, manager_id,)
8     # 写入数据库
9     db_helper.write(sql, vars)

  做到这一步,三个回顾的经过主键值读取数据表记录实体的ORM方法就完毕了。

  3.纵然它只是对点名表单操作时才用到,就将它包裹到该逻辑层子类,方便该子类要用届期得以随即调用

  要封装成ORM的艺术,作者急需须求在意下边几项职业:

  对于字段值,假若为字符串、具体时刻、json等品种的,也正是说必要用单撇号括起来的,我们就必要调用string_helper模块的string方法开展更改,它可感到变量扩张单撇号,要是一向赋字符串值,生成的sql语句是还没单撇号的,这里要注意一下

  最后调用数据库操作类db_helper来实行sql语句(这里运用widh方法来早先化数据库操作类),将实行后的结果回到主程序

  还应该有登陆接口最尾部,更新管理员最终登录时、登陆ip和丰富登录次数供给退换,具体代码如下:

  在上少年老成章中,大家已经创办好ORM的基类了,接下去要做的正是将基类的常用方法生龙活虎风流倜傥达成。

  产品分类的删除分类接口大家会看出它的代码与产物删除接口大概,不过多了一个该分类是不是曾经被引述的二个判别,对于那个上边特地求证一下

 1 #!/usr/bin/evn python
 2 # coding=utf-8
 3 
 4 import unittest
 5 from logic import product_logic
 6 
 7 class DbHelperTest(unittest.TestCase):
 8     """数据库操作包测试类"""
 9 
10     def setUp(self):
11         """初始化测试环境"""
12         print('------ini------')
13 
14     def tearDown(self):
15         """清理测试环境"""
16         print('------clear------')
17 
18     def test(self):
19         ##############################################
20         # 只需要看这里,其他代码是测试用例的模板代码 #
21         ##############################################
22         # 实例化product表操作类ProductLogic
23         _product_logic = product_logic.ProductLogic()
24         # 执行get_model_for_pk()方法,获取记录实体
25         model = _product_logic.get_model_for_pk(2)
26         print(model)
27 
28         ##############################################
29 
30 if __name__ == '__main__':
31     unittest.main()

  细心的仇人会意识,ORM模块的缓存部分,多了一个get_model_for_cache_of_where(卡塔尔方法,上面笔者来验证一下它的用项。

  然后从来调用默许项查询字段名称self.__column_name_list和表名称self.__table_name来合成sql语句。例如self.__column_name_list开始值为*,self.__table_name初阶值为product,那么合成的sql语句为:select * from product where id=1

 

  在写ORM模块时,大家已经对成品接口的分页查询、新添、改良、获取钦定产品实业接口已经重构好了,还剩余删除接口未形成

 

  当您习感觉常这种写法今后,你会开掘完毕各种接口会变得极度的从简与福利,开垦进程比此前也升高了成百上千

    def exists(self, wheres):
        """检查指定条件的记录是否存在"""
        return self.get_count(wheres) > 0

本文由时时app平台注册网站发布于编程知识,转载请注明出处:我的第一个python web开发框架(33)——接口代码

关键词: