首页 > 编程语言 > 详细

我的第一个python web开发框架(29)——定制ORM(六)

时间:2018-08-15 22:06:07      阅读:123      评论:0      收藏:0      [点我收藏+]

  在开发中,查询操作是使用最多的,而查询列表是其中之一,查询列表可分为分页查询和不分页查询(它们之间多了一次总记录数查询),还可以分为单表查询和多表关联查询,返回的结构体根据前端使用的表单框架不同而有所区别。

  我们先看看,对于列表分页查询,在接口中是如何处理的

技术分享图片
 1 @get(/api/product/)
 2 def callback():
 3     """
 4     获取列表数据
 5     """
 6     # 设置查询条件
 7     wheres = ‘‘
 8     # 产品分类id
 9     product_class_id = convert_helper.to_int0(web_helper.get_query(product_class_id, 产品分类id, is_check_null=False))
10     if product_class_id > 0:
11         wheres = where product_class_id= + str(product_class_id)
12     # 页面索引
13     page_number = convert_helper.to_int1(web_helper.get_query(page, ‘‘, is_check_null=False))
14     # 页面显示记录数量
15     page_size = convert_helper.to_int0(web_helper.get_query(rows, ‘‘, is_check_null=False))
16     # 排序字段
17     sidx = web_helper.get_query(sidx, ‘‘, is_check_null=False)
18     # 顺序还是倒序排序
19     sord = web_helper.get_query(sord, ‘‘, is_check_null=False)
20     # 初始化排序字段
21     order_by = id desc
22     ### 设置排序 ###
23     if sidx:
24         order_by = sidx +   + sord
25     # 类型
26     type = web_helper.get_query(type, 类型, is_check_null=False)
27     # 判断是否是前台提交获取数据
28     if type != backstage:
29         # 判断是否已经存在查询条件了,是的话在原查询条件后面拼接
30         if wheres:
31             wheres = wheres +  and is_enable=1
32         else:
33             wheres = where is_enable=1
34 
35     #############################################################
36     # 初始化输出格式(前端使用jqgrid列表,需要指定输出格式)
37     data = {
38         records: 0,
39         total: 0,
40         page: 1,
41         rows: [],
42     }
43     #############################################################
44     # 执行sql,获取指定条件的记录总数量
45     sql = select count(1) as records from product %(wheres)s % {wheres: wheres}
46     result = db_helper.read(sql)
47     # 如果查询失败或不存在指定条件记录,则直接返回初始值
48     if not result or result[0][records] == 0:
49         return data
50     # 保存总记录数量
51     data[records] = result[0].get(records, 0)
52 
53     #############################################################
54     ### 设置分页索引与页面大小 ###
55     # 设置分页大小
56     if page_size is None or page_size <= 0:
57         page_size = 10
58     # 计算总页数
59     if data[records] % page_size == 0:
60         page_total = data[records] // page_size
61     else:
62         page_total = data[records] // page_size + 1
63     # 记录总页面数量
64     data[total] = page_total
65 
66     # 判断提交的页码是否超出范围
67     if page_number < 1 or page_number > page_total:
68         page_number = page_total
69     # 记录当前页面索引值
70     data[page] = page_number
71 
72     # 计算当前页面要显示的记录起始位置
73     record_number = (page_number - 1) * page_size
74     # 设置查询分页条件
75     paging =  limit  + str(page_size) +  offset  + str(record_number)
76 
77     #############################################################
78 
79     # 组合sql查询语句
80     sql = "select * from product %(wheres)s order by %(orderby)s %(paging)s" % 81            {wheres: wheres, orderby: order_by, paging: paging}
82     # 读取记录
83     result = db_helper.read(sql)
84     if result:
85         # 存储记录
86         data[rows] = result
87 
88     if data:
89         # 直接输出json
90         return web_helper.return_raise(json.dumps(data, cls=json_helper.CJsonEncoder))
91     else:
92         return web_helper.return_msg(-1, "查询失败")
View Code

  代码看起来很长,有点复杂,对于这种列表分页查询,如果不封装的话,开发时复制粘贴就很容易出错,所以我们需要重新处理才行。

  从上面代码可以看到,具体功能分为几个部分:

  第一部分(9到33行)是接收并组合查询条件,接收分页参数和排序参数

  第二部分(37到42行)是初始化结果输出参数

  第三部分(44到51行)是获取查询总记录数

  第四部分(55到75行)是计算总页数,计算当前分页位置要显示的记录位置区间

  第五部分(80到92行)是组合查询语句,查询并输出结果

  除了产品列表这个接口,大家可以看看产品分类列表接口,会发现两个接口第二部分到第五部分都差不多,所以我们封装ORM时,可以将这些相似部分进行处理,将它们封装到ORM对应的方法里。

 

  首先,我们对上面代码的分析,可以提炼出分页查询方法需要有下面参数:查询字段、查询条件、当前分页索引值、每页显示记录数量、排序。如果是多表查询时,我们的ORM是直接绑定当前表单的就不适用了,所以还需要有个设置表名的参数,好灵活处理各种需求,根据这些要求,我们可以创建好列表查询方法:

def get_list(self, column_name_list=‘‘, wheres=‘‘, page_number=None, page_size=None, orderby=None, table_name=None):
    """
    获取指定条件的数据库记录集
    :param column_name_list:      查询字段
    :param wheres:      查询条件
    :param page_number:   分页索引值
    :param page_size:    分页大小, 存在值时才会执行分页
    :param orderby:     排序规则
    :param table_name:     查询数据表,多表查询时需要设置
    :return: 返回记录集总数量与分页记录集
        {‘records‘: 0, ‘total‘: 0, ‘page‘: 0, ‘rows‘: []}
    """

  在接收到这些参数以后,我们需要对相关参数进行初始化操作,方便后续代码的执行

 1     # 初始化输出参数:总记录数量与列表集
 2     data = {
 3         records: 0,   # 总记录数
 4         total: 0,     # 总页数
 5         page: 1,      # 当前页面索引
 6         rows: [],     # 查询结果(记录列表)
 7     }
 8     # 初始化查询数据表名称
 9     if not table_name:
10         table_name = self.__table_name
11     # 初始化查询字段名
12     if not column_name_list:
13         column_name_list = self.__column_name_list
14     # 初始化查询条件
15     if wheres:
16         # 如果是字符串,表示该查询条件已组装好了,直接可以使用
17         if isinstance(wheres, str):
18             wheres = where  + wheres
19         # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
20         elif isinstance(wheres, list):
21             wheres = where  +  and .join(wheres)
22     # 初始化排序
23     if not orderby:
24         orderby = self.__pk_name +  desc
25     # 初始化分页查询的记录区间
26     paging = ‘‘

  这里是对传入的参数和后续需要用到的参数进行初始化操作

  这里需要初始化查询结果输出参数结构,在进行记录数查询时,如果没有记录存在,就可以直接将结果返回出去了;

  默认数据表为当前类实体指定的表名称,如果进行多表联合查询时,就需要设置多表联合查询的组合表名称,比如:product left join product_class on product.product_class_id = product_class.id

  同时我们还需要设置查询字段内容,如果想查询出所有字段,直接使用*,如果只想要输出指定的几个字段值,则可以填写这几个字段值,比如:id,name,content

  在查询时,有时不需要查询条件,这时我们可以不填写条件,如果有指定条件时,我们可以将它们组合好,也可以放到list中。它们的区别在于,有多个查询条件时,我们有时很难判断当前条件前需不需要添加and,这时我们就可以使用‘ and ‘.join(列表) 来进行合成了,当然用list方式条件之间只能是and的关系。对于复杂的条件,我们可以组合好以后提交进来直接使用;

  在查询时,如果没有指定排序方式,我们默认使用主键倒序来进行排序

 

  在分页列表操作时,我们通常需要获取总记录数返回给前端,所以在执行查询前,我们需要获取当前查询条件的总记录数

 1     with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 2         #############################################################
 3         # 判断是否需要进行分页
 4         if not page_size is None:
 5             ### 执行sql,获取指定条件的记录总数量
 6             sql = select count(1) as records from %(table_name)s %(wheres)s  %  7                   {table_name: table_name, wheres: wheres}
 8             result = db.execute(sql)
 9             # 如果查询失败或不存在指定条件记录,则直接返回初始值
10             if not result or result[0][records] == 0:
11                 return data
12 
13             # 设置记录总数量
14             data[records] = result[0].get(records)

  加上if not page_size is None判断,是因为有时候我们查询时,不需要分页操作,直接将所有记录输出了,这里加上判断可以减少不必要的记录总数量查询

 

  当我们获取到总记录数量以后,我们需要根据前端页面显示的记录数进行计算,计算出总页面数量,排除页面索引值超出限制可能会带来的异常,还有需要计算当前页面查询时对应的记录起始位置,组合分页查询条件pagin

 1             #########################################################
 2             ### 设置分页索引与页面大小 ###
 3             if page_size <= 0:
 4                 page_size = 10
 5             # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
 6             if data[records] % page_size == 0:
 7                 page_total = data[records] // page_size
 8             else:
 9                 page_total = data[records] // page_size + 1
10             # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
11             if page_number < 1 or page_number > page_total:
12                 page_number = page_total
13             # 记录总页面数量
14             data[total] = page_total
15             # 记录当前页面值
16             data[page] = page_number
17             # 计算当前页面要显示的记录起始位置(limit指定的位置)
18             record_number = (page_number - 1) * page_size
19             # 设置查询分页条件
20             paging =  limit  + str(page_size) +  offset  + str(record_number)
21         #############################################################

 

  最后,我们组合最终查询条件,查询并输出结果

 1         ### 按条件查询数据库记录
 2         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" %  3               {column_name_list: column_name_list,
 4                table_name: table_name,
 5                wheres: wheres,
 6                orderby: orderby,
 7                paging: paging}
 8         result = db.execute(sql)
 9         if result:
10             data[rows] = result
11             # 不需要分页查询时,直接在这里设置总记录数
12             if page_size is None:
13                 data[records] = len(result)
14 
15     return data

 

  完整代码

 

 1    def get_list(self, column_name_list=‘‘, wheres=‘‘, page_number=None, page_size=None, orderby=None, table_name=None):
 2         """
 3         获取指定条件的数据库记录集
 4         :param column_name_list:      查询字段
 5         :param wheres:      查询条件
 6         :param page_number:   分页索引值
 7         :param page_size:    分页大小, 存在值时才会执行分页
 8         :param orderby:     排序规则
 9         :param table_name:     查询数据表,多表查询时需要设置
10         :return: 返回记录集总数量与分页记录集
11             {‘records‘: 0, ‘total‘: 0, ‘page‘: 0, ‘rows‘: []}
12         """
13         # 初始化输出参数:总记录数量与列表集
14         data = {
15             records: 0,   # 总记录数
16             total: 0,     # 总页数
17             page: 1,      # 当前页面索引
18             rows: [],     # 查询结果(记录列表)
19         }
20         # 初始化查询数据表名称
21         if not table_name:
22             table_name = self.__table_name
23         # 初始化查询字段名
24         if not column_name_list:
25             column_name_list = self.__column_name_list
26         # 初始化查询条件
27         if wheres:
28             # 如果是字符串,表示该查询条件已组装好了,直接可以使用
29             if isinstance(wheres, str):
30                 wheres = where  + wheres
31             # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
32             elif isinstance(wheres, list):
33                 wheres = where  +  and .join(wheres)
34         # 初始化排序
35         if not orderby:
36             orderby = self.__pk_name +  desc
37         # 初始化分页查询的记录区间
38         paging = ‘‘
39 
40         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
41             #############################################################
42             # 判断是否需要进行分页
43             if not page_size is None:
44                 ### 执行sql,获取指定条件的记录总数量
45                 sql = select count(1) as records from %(table_name)s %(wheres)s  % 46                       {table_name: table_name, wheres: wheres}
47                 result = db.execute(sql)
48                 # 如果查询失败或不存在指定条件记录,则直接返回初始值
49                 if not result or result[0][records] == 0:
50                     return data
51 
52                 # 设置记录总数量
53                 data[records] = result[0].get(records)
54 
55                 #########################################################
56                 ### 设置分页索引与页面大小 ###
57                 if page_size <= 0:
58                     page_size = 10
59                 # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
60                 if data[records] % page_size == 0:
61                     page_total = data[records] // page_size
62                 else:
63                     page_total = data[records] // page_size + 1
64                 # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
65                 if page_number < 1 or page_number > page_total:
66                     page_number = page_total
67                 # 记录总页面数量
68                 data[total] = page_total
69                 # 记录当前页面值
70                 data[page] = page_number
71                 # 计算当前页面要显示的记录起始位置(limit指定的位置)
72                 record_number = (page_number - 1) * page_size
73                 # 设置查询分页条件
74                 paging =  limit  + str(page_size) +  offset  + str(record_number)
75             #############################################################
76 
77             ### 按条件查询数据库记录
78             sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % 79                   {column_name_list: column_name_list,
80                    table_name: table_name,
81                    wheres: wheres,
82                    orderby: orderby,
83                    paging: paging}
84             result = db.execute(sql)
85             if result:
86                 data[rows] = result
87                 # 不需要分页查询时,直接在这里设置总记录数
88                 if page_size is None:
89                     data[records] = len(result)
90 
91         return data

 

 

  我们在单元测试中跑一跑,看看结果吧

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

  输出结果

 1 -- -- --ini-- -- --
 2 {
 3     records: 4,
 4     total: 1,
 5     page: 1,
 6     rows: [{
 7         content: ‘‘,
 8         name: 名称,
 9         place_of_origin: ‘‘,
10         front_cover_img: ‘‘,
11         code: 201808031245678,
12         quality_guarantee_period: ‘‘,
13         product_class_id: 1,
14         standard: ‘‘,
15         add_time: datetime.datetime(2018, 8, 3, 16, 51, 3),
16         id: 15,
17         is_enable: 0
18     }, {
19         content: ‘‘,
20         name: 张三,
21         place_of_origin: ‘‘,
22         front_cover_img: ‘‘,
23         code: 201807251234568,
24         quality_guarantee_period: ‘‘,
25         product_class_id: 0,
26         standard: ‘‘,
27         add_time: datetime.datetime(2018, 8, 3, 0, 14, 14),
28         id: 14,
29         is_enable: 0
30     }]
31 }
32 -- -- --clear-- -- --

 

  前面的接口我们也改造一下

 1 @get(/api/product/)
 2 def callback():
 3     """
 4     获取列表数据
 5     """
 6     # 产品分类id
 7     product_class_id = convert_helper.to_int0(web_helper.get_query(product_class_id, 产品分类id, is_check_null=False))
 8     # 类型
 9     type = web_helper.get_query(type, 类型, is_check_null=False)
10     # 页面索引
11     page_number = convert_helper.to_int1(web_helper.get_query(page, ‘‘, is_check_null=False))
12     # 页面显示记录数量
13     page_size = convert_helper.to_int0(web_helper.get_query(rows, ‘‘, is_check_null=False))
14     # 排序字段
15     sidx = web_helper.get_query(sidx, ‘‘, is_check_null=False)
16     # 顺序还是倒序排序
17     sord = web_helper.get_query(sord, ‘‘, is_check_null=False)
18 
19     # 设置查询条件
20     wheres = []
21     if product_class_id > 0:
22         wheres.append(product_class_id= + str(product_class_id))
23     # 判断是否是前台提交获取数据
24     if type != backstage:
25         wheres.append(is_enable=1)
26 
27     # 初始化排序字段
28     orderby = None
29     ### 设置排序 ###
30     if sidx:
31         orderby = sidx +   + sord
32 
33     # 实例化product表操作类ProductLogic
34     _product_logic = product_logic.ProductLogic()
35     result = _product_logic.get_list(*, wheres, page_number, page_size, orderby)
36     if result:
37         return web_helper.return_raise(json.dumps(result, cls=json_helper.CJsonEncoder))
38     else:
39         return web_helper.return_msg(-1, "查询失败")

 

  这样处理以后,代码看起来舒服多了

 

 

版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

python开发QQ群:669058475    作者博客:http://www.cnblogs.com/EmptyFS/

我的第一个python web开发框架(29)——定制ORM(六)

原文:https://www.cnblogs.com/EmptyFS/p/9483706.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!