彩世界开奖app官网-彩世界平台官方网址(彩票平台)
做最好的网站
来自 计算机编程 2019-11-28 06:45 的文章
当前位置: 彩世界开奖app官网 > 计算机编程 > 正文

自家的率先个python web开辟框架(36卡塔 尔(阿拉

 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 = ''

python开发QQ群:669058475、733466321 作者博客:

我的第一个python web开发框架(17)——产品管理,pythonweb

  这是后台管理系统最后一个功能,产品管理,它的接口与页面功能与上一章差不多。

图片 1

 

图片 2

 

  获取产品列表接口

图片 3 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', '', 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 if sidx: 23 order_by = sidx ' ' sord 24 25 ############################################################# 26 # 初始化输出格式(前端使用jqgrid列表,需要指定输出格式) 27 data = { 28 'records': 0, 29 'total': 0, 30 'page': 1, 31 'rows': [], 32 } 33 ############################################################# 34 # 执行sql,获取指定条件的记录总数量 35 sql = 'select count(1) as records from product %(wheres)s' % {'wheres': wheres} 36 result = db_helper.read(sql) 37 # 如果查询失败或不存在指定条件记录,则直接返回初始值 38 if not result or result[0]['records'] == 0: 39 return data 40 # 保存总记录数量 41 data['records'] = result[0].get('records', 0) 42 43 ############################################################# 44 ### 设置分页索引与页面大小 ### 45 # 设置分页大小 46 if page_size is None or page_size <= 0: 47 page_size = 10 48 # 计算总页数 49 if data['records'] % page_size == 0: 50 page_total = data['records'] // page_size 51 else: 52 page_total = data['records'] // page_size 1 53 # 记录总页面数量 54 data['total'] = page_total 55 56 # 判断提交的页码是否超出范围 57 if page_number < 1 or page_number > page_total: 58 page_number = page_total 59 # 记录当前页面索引值 60 data['page'] = page_number 61 62 # 计算当前页面要显示的记录起始位置 63 record_number = (page_number

  • 1) * page_size 64 # 设置查询分页条件 65 paging = ' limit ' str(page_size) ' offset ' str(record_number) 66 ### 设置排序 ### 67 if not order_by: 68 order_by = 'id desc' 69 ############################################################# 70 71 # 组合sql查询语句 72 sql = "select * from product %(wheres)s order by %(orderby)s %(paging)s" % 73 {'wheres': wheres, 'orderby': order_by, 'paging': paging} 74 # 读取记录 75 result = db_helper.read(sql) 76 if result: 77 # 存储记录 78 data['rows'] = result 79 80 if data: 81 # 直接输出json 82 return web_helper.return_raise(json.dumps(data, cls=json_helper.CJsonEncoder)) 83 else: 84 return web_helper.return_msg(-1, "查询失败") View Code

  这个接口多了按产品分类id查询的条件,如果少了这个的话,直接将产品分类字段替换为产品字段变量就可以了。

  大家可以看到这里的代码好像有点复杂。是的,这里要进行分页查询进行了分页处理,所以代码有点多,不过写了很详细的注释,只要你对python的基本语法、字典的处理理解,然后对之前工具函数那里按要求重写过测试用例,那么对阅读这段代码是没有什么大问题的。

  下面再重新帮大家熟悉一下前面讲述过的工具函数

product_class_id = convert_helper.to_int0(web_helper.get_query('product_class_id', '产品分类id', is_check_null=False))

  这是获取客户端(HTML)用AJAX提交上来的产品分类id接收处理,如果你认真看过前面工具函数内容的话,看到web_helper.get_query()这个函数应该会很熟悉,它就是获取GET方式提交值的接收函数,第一个参数是要接收的变量名称,第二个参数是这个变量的中文说明,第三个是在接收参数时,是否做非空判断,当前设置为这不是必填项。默认它为True,当为True时,如果客户端没有提交这个参数值,则系统自动会返回“xxx 不允许为空”,这个xxx就是第二个参数,也就是当前变量的中文说明,还有其他参数大家可以打看web_helper.py查看。

  convert_helper.to_int0()这个函数,在前面工具函数第一篇中讲到的函数,它会将接收到的参数字符串转为int类型值,如果这个参数小于0时,会自动使用默认值0代替。

 

sql = 'select count(1) as records from product %(wheres)s' % {'wheres': wheres}

  使用习惯ORM的朋友可能会不太习惯直接写sql语句,本系列第一部分主要面向没有什么基础的朋友,所以尽量不封装各种类和函数,这样大家直接看到内容会更容易理解。第二部分会教大家自己简单封装一个ORM,到时重构后重复代码就会减少一大半。

  上面这行是获取当前查询有多少条记录的sql语句,熟悉python字符串替换的朋友应该会很熟悉,它会将字符串%后面的字典内容替代字符串中对应的键值,如果wheres值为空时,则替换空值,即将%(wheres)s这个键值替换掉。

  python的字符串替换有多种方式,而这里使用字典方式来替换会让代码可读性更高,而且字典中各个值的位置不需要按固定方式摆放,不容易出错。

 

  获取指定id的记录实体

 1 @get('/api/product/<id:int>/')
 2 def callback(id):
 3     """
 4     获取指定记录
 5     """
 6     sql = """select * from product where id = %s""" % (id,)
 7     # 读取记录
 8     result = db_helper.read(sql)
 9     if result:
10         # 直接输出json
11         return web_helper.return_msg(0, '成功', result[0])
12     else:
13         return web_helper.return_msg(-1, "查询失败")

  这段代码比较简单,第6行使用的就是%s替换字符串方式,后面的元组(id,)  好像python3以后元组里不加逗号替换也没有问题,python2是一定要加的。

 

  添加产品与修改产品接口

图片 4 1 @post('/api/product/') 2 def callback(): 3 """ 4 新增记录 5 """ 6 name = web_helper.get_form('name', '产品名称') 7 code = web_helper.get_form('code', '产品编码') 8 product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '产品分类')) 9 standard = web_helper.get_form('standard', '产品规格') 10 quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保质期') 11 place_of_origin = web_helper.get_form('place_of_origin', '产地') 12 front_cover_img = web_helper.get_form('front_cover_img', '封面图片') 13 content = web_helper.get_form('content', '产品描述', is_check_special_char=False) 14 # 防sql注入攻击处理 15 content = string_helper.filter_str(content, "'") 16 # 防xss攻击处理 17 content = string_helper.clear_xss(content) 18 is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否启用')) 19 20 # 添加记录(使用returning这个函数能返回指定的字段值,这里要求返回新添加记录的自增id值) 21 sql = """insert into product (name, code, product_class_id, standard, quality_guarantee_period, 22 place_of_origin, front_cover_img, content, is_enable) 23 values (%s, %s, %s, %s, %s, %s, %s, %s, %s) returning id""" 24 vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content, is_enable) 25 # 写入数据库 26 result = db_helper.write(sql, vars) 27 # 判断是否提交成功 28 if result and result[0].get('id'): 29 return web_helper.return_msg(0, '成功') 30 else: 31 return web_helper.return_msg(-1, "提交失败") 32 33 34 @put('/api/product/<id:int>/') 35 def callback(id): 36 """ 37 修改记录 38 """ 39 40 name = web_helper.get_form('name', '产品名称') 41 code = web_helper.get_form('code', '产品编码') 42 product_class_id = convert_helper.to_int0(web_helper.get_form('product_class_id', '产品分类')) 43 standard = web_helper.get_form('standard', '产品规格') 44 quality_guarantee_period = web_helper.get_form('quality_guarantee_period', '保质期') 45 place_of_origin = web_helper.get_form('place_of_origin', '产地') 46 front_cover_img = web_helper.get_form('front_cover_img', '封面图片') 47 content = web_helper.get_form('content', '产品描述', is_check_special_char=False) 48 # 防sql注入攻击处理 49 content = string_helper.filter_str(content, "'") 50 # 防xss攻击处理 51 content = string_helper.clear_xss(content) 52 is_enable = convert_helper.to_int0(web_helper.get_form('is_enable', '是否启用')) 53 54 # 编辑记录 55 sql = """ 56 update product 57 set name=%s, code=%s, product_class_id=%s, standard=%s, quality_guarantee_period=%s, 58 place_of_origin=%s, front_cover_img=%s, content=%s, is_enable=%s 59 where id=%s returning id""" 60 vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content, 61 is_enable, id) 62 # 写入数据库 63 result = db_helper.write(sql, vars) 64 # 判断是否提交成功 65 if result and result[0].get('id'): 66 return web_helper.return_msg(0, '成功') 67 else: 68 return web_helper.return_msg(-1, "提交失败") View Code

  使用非get方式提交时,即使用post、put、delete等方式提交参数时,需要使用web_helper.get_form()函数来接收,这一点大家要注意,不然就会获取不到客户端提交的参数值

    # 添加记录(使用returning这个函数能返回指定的字段值,这里要求返回新添加记录的自增id值)
    sql = """insert into product (name, code, product_class_id, standard, quality_guarantee_period,
                place_of_origin, front_cover_img, content, is_enable)
              values (%s, %s, %s, %s, %s, %s, %s, %s, %s) returning id"""
    vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content, is_enable)
    # 写入数据库
    result = db_helper.write(sql, vars)

  新增记录时,容易出错的地方是参数中的%s与字段数量不匹配,这里大家要注意一下。另外,在insert语句的后尾最好加上returning id或returning *  返回新增记录值或整个记录实体,方便用来判断是否插入成功,如果返回这些内容的话,比较难判断数据库记录是否添加成功了

    # 编辑记录
    sql = """
          update product
            set name=%s, code=%s, product_class_id=%s, standard=%s, quality_guarantee_period=%s,
                place_of_origin=%s, front_cover_img=%s, content=%s, is_enable=%s
          where id=%s returning id"""
    vars = (name, code, product_class_id, standard, quality_guarantee_period, place_of_origin, front_cover_img, content,
            is_enable, id)
    # 写入数据库
    result = db_helper.write(sql, vars)

  更新记录时,参数元组中记录要将记录的id值放进来,不然也会出现sql执行异常的问题,这个也是容易出错的地方。

 

  删除记录接口

 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, "删除失败")

  

  前端代码大家自己可以比较一下上一章,看看有什么不同

  非常感谢Sunshine-X 的提醒,在产品编辑页面的js中,添加了保存成功后jqgrid表格刷新代码(本人前端比较菜)

  后面附上完整的项目代码

 

 

  本文对应的源码下载

 

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

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

 

web开发框架(17)——产品管理,pythonweb 这是后台管理系统最后一个功能,产品管理,它的接口与页面功能与上一章差不多...

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

  删除接口跟前端产品分类删除接口一样,在删除前需要判断当前菜单是否已被引用(即当前菜单下是否存在子菜单)

 

  前端通过AJAX获取菜单列表hmtl代码,然后添加到后台左栏菜单列表中就实现我们想要的效果了

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

 1 @get('/api/system/menu_info/tree/') 2 def callback(): 3     """ 4     获取列表数据 5     """ 6     _menu_info_logic = menu_info_logic.MenuInfoLogic() 7     # 读取记录 8     result = _menu_info_logic.get_list('id, parent_id, name, not is_leaf as open', 'is_leaf=false', orderby='sort asc') 9     if result:10         return web_helper.return_msg(0, "成功", {'tree_list': result.get('rows')})11     else:12         return web_helper.return_msg(-1, "查询失败")

 

 1 @post('/api/system/menu_info/') 2 def callback(): 3     """ 4     新增记录 5     """ 6     name = web_helper.get_form('name', '菜单名称') 7     icon = web_helper.get_form('icon', '菜单小图标', True, 10, False, is_check_special_char=False) 8     icon = icon.replace(''', '').replace('|', '').replace('%', '') 9     page_url = web_helper.get_form('page_url', '页面URL', is_check_null=False)10     interface_url = web_helper.get_form('interface_url', '接口url', is_check_null=False, is_check_special_char=False)11     # 替换编码12     interface_url = interface_url.replace('@', '').replace(''', '').replace('|', '').replace('%', '')13     parent_id = convert_helper.to_int0(web_helper.get_form('parent_id', '父id', is_check_null=False))14     sort = convert_helper.to_int0(web_helper.get_form('sort', '排序', is_check_null=False))15     is_leaf = web_helper.get_form('is_leaf', '是否最终节点', is_check_null=False)16     is_show = web_helper.get_form('is_show', '是否显示', is_check_null=False)17     is_enabled = web_helper.get_form('is_enabled', '是否启用', is_check_null=False)18 19     _menu_info_logic = menu_info_logic.MenuInfoLogic()20     # 计算深度级别,即当前菜单在哪一级21     if parent_id == 0:22         level = 023     else:24         level = _menu_info_logic.get_value_for_cache(parent_id, 'level')   125     # 如果没有设置排序,则自动获取当前级别最大的序号加126     if sort == 0:27         sort = _menu_info_logic.get_max('parent_id', 'parent_id='   str(parent_id))   128 29     # 组合更新字段30     fields = {31         'name': string,32         'icon': string,33         'page_url': string,34         'interface_url': string(interface_url),35         'parent_id': parent_id,36         'sort': sort,37         'level': level,38         'is_leaf': is_leaf,39         'is_show': is_show,40         'is_enabled': is_enabled,41     }42     # 新增记录43     result = _menu_info_logic.add_model44     if result:45         return web_helper.return_msg(0, '提交成功')46     else:47         return web_helper.return_msg(-1, "提交失败")

 

  

 

  jqGrid会通过接口,将当前页面索引值page、页面显示记录行数rows、排序字段sidx和排序方式sord提交到服务器端接口,如果我们使用树列表,它还会提交当前节点id参数nodeid

 

图片 5

 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         #############################################################

  2.不需要再计算当前菜单所在层级的深度

 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()

  对于菜单管理的改造,完成上面这些项就算完厉了。对于菜单权限的控制,后续完成整个改造后会专门讲解。

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

  权限系统中的部门管理,它的基本功能和菜单功能相似,所以就不开新章节进行讲解,大家可以根据数据结构尝试编写,也可以参考本节提供的源码进行研究。

View Code

  所以我们在服务器端接口需要做好这几个参数的接收与使用操作,然后我们通过调用前面实现的ORM的get_list方法,就可以获取对应的数据返回给客户端了,具休代码如下:

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

  要开发一个菜单管理功能,离不开这些功能:菜单列表展示(需要菜单列表获取接口)、新增菜单、编辑菜单(获取菜单记录以及提交修改接口)、删除菜单,由于菜单是多层级的关系,所以还需要增加菜单树列表获取接口来绑定菜单层级,在主页面还需要增加菜单列表项输出接口,用来展示菜单项。

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

  大家可以比较一下新增与编辑接口代码,可以发现代码几乎都是一样的。

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

  图片 6

 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

  完成后直接填写参数就可以提交新增菜单记录了。

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

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

 

  首先我们通过查看左栏菜单列表的html代码,提取出菜单html展示代码

 

  排序可以输入任意的数字,通过从 小到大顺序排列菜单项,为了方便排序项可以自行累加,代码中可以获取当前菜单层级最大值加1的方式来进行赋值

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

  对于编辑接口,它基本上和新增接口代码相差不大,区别地方有下面几点:

 

  PS:部门管理中,部门编码生成是一个比较特殊的方法,需要多debug理解。

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

  最后增加删除接口

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

{    "data": {        "menu_html": "n                <dl id="menu-1">n                    <dt><i class="Hui-iconfont">&#xe62e;</i> 系统管理<i class="Hui-iconfont menu_dropdown-arrow">&#xe6d5;</i></dt>n                    <dd>n                        <ul>n                n                        <li><a data-href="menu_info.html" data-title="菜单管理" href="javascript:void">菜单管理</a></li>n                    n                        </ul>n                    </dd>n                </dl>n                    "    },    "msg": "成功",    "state": 0}

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

<aside class="Hui-aside">    <div class="menu_dropdown bk_2" id="menu">    </div></aside><script type="text/javascript">    $(function () {        $.ajax({            url: "/api/main/menu_info/?"   100 * Math.random(),            type: "GET",            dataType:'json',            success: function  {                if (checkLogin(data, true))                {                    $("#menu").html(data.data.menu_html);                    $.Huifold(".menu_dropdown dl dt",".menu_dropdown dl dd","fast",1,"click");                }            }        });    });</script>

 

  执行后会输出下面结果:

  完整代码

  为了方便后续权限的管理改造,我们在接口中组合菜单代码来实现菜单的展示效果。

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

  前端菜单管理的hmtl页面大家自行下载源码包查看,下面是完成后展示效果

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

  在正式编写菜单管理功能之前,我们需要先在逻辑层中添加菜单逻辑类:menu_info_logic.py,继承前面我们开发的ORM基类,让当前的菜单管理逻辑类拥有ORM的所有方法。

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

  我们在后台main.html中添加菜单,方便登录后台查看效果

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

  22行是设置查询条件,默认菜单列表我们只显示第一级菜单,也就是父id为0的菜单。在列表第一次加载时,列表提交上来的nodeid为空(即父节点为默认为0),所以设置查询条件时父节点会赋值为parent_id=0。当我们点击树菜单展开时,才加载下一级菜单出来,这时jqGrid控件会再次访问接口,提交当前要展开发节点id给接口,接口接收到参数以后返回对应的子节点列表给客户端。

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

  对于后台管理系统来说,要做好权限管理离不开菜单项和页面按钮控件功能的管理。由于程序没法智能的知道有什么菜单和控件,哪些人拥有哪些操作权限,所以首先要做的是菜单管理功能,将需要管理的菜单项和各个功能项添加到菜单管理表中,方便后续权限控制管理。

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

  上级菜单选项,这里我们点击选择时,需要显示菜单树列表,让我们选择当前新增菜单项所属菜单层级,方便菜单层级的管理,如果为顶级菜单,则不需要进行选择

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

  然后在接口中,获取设置为显示并启用状态的菜单列表

 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')

  7到18行,是接收参数。

 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-- -- --

  菜单管理项添加完成后,列表效果图

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

  先看看新增页面效果(页面内容项一般我们是根据数据字典和原型来设计的,大家可以参照一下上一章菜单管理的数据结构)

  输出结果

  接下来我们先实现菜单列表获取接口,由第一部分的后端管理功能可以知道,我们前端使用的是jqGrid插件,这一块我们在前面已经实现过了,而ORM中也封装好对应的方法,所以直接调用就可以了。(这个接口在实现时,我们要了解清楚的是,前端插件jqGrid它会传递什么参数和需要返回什么格式的数据回去)

 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

  3.将新增方法add_model()更改为edit_model()方法

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

  20行初始化菜单逻辑类

图片 7图片 8

 1 @get('/system/menu_info/') 2 def callback(): 3     """ 4     获取列表数据 5     """ 6     # 菜单列表中,当前节点id,即父节点id 7     parent_id = convert_helper.to_int0(web_helper.get_query('nodeid', '', is_check_null=False)) 8     # 页面索引 9     page_number = convert_helper.to_int1(web_helper.get_query('page', '', is_check_null=False))10     # 页面页码与显示记录数量11     page_size = convert_helper.to_int0(web_helper.get_query('rows', '', is_check_null=False))12     # 接收排序参数13     sidx = web_helper.get_query('sidx', '', is_check_null=False)14     sord = web_helper.get_query('sord', '', is_check_null=False)15     # 初始化排序字段16     order_by = 'sort asc'17     if sidx:18         order_by = sidx   ' '   sord19 20     _menu_info_logic = menu_info_logic.MenuInfoLogic()21     # 读取记录22     wheres = 'parent_id='   str(parent_id)23     result = _menu_info_logic.get_list('*', wheres, page_number, page_size, order_by)24     if result:25         return json.dumps26     else:27         return web_helper.return_msg(-1, "查询失败")
 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, "查询失败")

  通过循环判断,拼接一级菜单和二级菜单项的html输出代码

 

图片 9

 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, "查询失败")

图片 10

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

  我们需要接收页面提交上来的这些参数,然后向数据库中添加一条记录

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

 1 @get('/api/main/menu_info/') 2 def callback(): 3     """ 4     主页面获取菜单列表数据 5     """ 6     _menu_info_logic = menu_info_logic.MenuInfoLogic() 7     # 读取记录 8     result = _menu_info_logic.get_list('*', 'is_show and is_enabled', orderby='sort') 9     if result:10         # 定义最终输出的html存储变量11         html = ''12         for model in result.get('rows'):13             # 提取出第一级菜单14             if model.get('parent_id') == 0:15                 # 添加一级菜单16                 temp = """17                 <dl >18                     <dt><i >%s</i> %s<i >&#xe6d5;</i></dt>19                     <dd>20                         <ul>21                 """ % {'id': model.get('id'), 'icon': model.get('icon'), 'name': model.get('name')}22                 html = html   temp23 24                 # 从所有菜单记录中提取当前一级菜单下的子菜单25                 for sub_model in result.get('rows'):26                     # 如果父id等于当前一级菜单id,则为当前菜单的子菜单27                     if sub_model.get('parent_id') == model.get('id'):28                         temp = """29                         <li><a data-href="%s" data-title="%s" href="javascript:void">%s</a></li>30                     """ % {'page_url': sub_model.get('page_url'), 'name': sub_model.get('name')}31                         html = html   temp32 33                 # 闭合菜单html34                 temp = """35                         </ul>36                     </dd>37                 </dl>38                     """39                 html = html   temp40 41         return web_helper.return_msg(0, '成功', {'menu_html': html})42     else:43         return web_helper.return_msg(-1, "查询失败")

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

  get_list是前端ORM中封装好的参数,它会返回jqGrid所需要的数据格式,所以第25行直接将符合jqGrid要求的数据返回给列表展示出来。

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

  最后将结果输出到前端展示出来

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

  1.为了减少菜单层级变更所造成的错误,在编辑记录接口我们需要屏蔽对父节点id的修改

 

  图片 11

 

  本文对应的源码下载(内附本章源码对应数据库表单和记录创建sql代码,上传的图片如果显示不了,可以nginx.conf配置的location项中添加upload,第一部分章节的nginx那里忘记添加了)

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

  图片 12

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

  新增菜单页面树列表我们使用的是zTree插件,它需要我们输出指定的数据格式才能正常显示,所以调用接口返回:id、parent_id、name、open这几个字段,在菜单项中,我们有是否最终节点的字段,所以查询条件中我们指定查询出所有非最终节点的项就可以了

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 @delete('/api/system/menu_info/<id:int>/') 2 def callback: 3     """ 4     删除指定记录 5     """ 6     _menu_info_logic = menu_info_logic.MenuInfoLogic() 7     # 判断要删除的节点是否有子节点,是的话不能删除 8     if _menu_info_logic.exists('parent_id='   str: 9         return web_helper.return_msg(-1, "当前菜单存在子菜单,不能直接删除")10 11     # 删除记录12     result = _menu_info_logic.delete_model13     if result:14         return web_helper.return_msg(0, '删除成功')15     else:16         return web_helper.return_msg(-1, "删除失败")
#!/usr/bin/env python# coding=utf-8from logic import _logic_basefrom config import db_configclass MenuInfoLogic(_logic_base.LogicBase):    """菜单管理表逻辑类"""    def __init__:        # 表名称        __table_name = 'menu_info'        # 初始化        _logic_base.LogicBase.__init__(self, db_config.DB, db_config.IS_OUTPUT_SQL, __table_name)

图片 13

  由于当前还没有数据,所以暂时列表是空的,下面我们创建添加和修改功能

 1 @put('/api/system/menu_info/<id:int>/') 2 def callback: 3     """ 4     修改记录 5     """ 6     name = web_helper.get_form('name', '菜单名称') 7     icon = web_helper.get_form('icon', '菜单小图标', True, 10, False, is_check_special_char=False) 8     icon = icon.replace(''', '').replace('|', '').replace('%', '') 9     page_url = web_helper.get_form('page_url', '页面URL', is_check_null=False)10     interface_url = web_helper.get_form('interface_url', '接口url', is_check_null=False, is_check_special_char=False)11     # 替换编码12     interface_url = interface_url.replace(''', '').replace('|', '').replace('%', '')13     parent_id = convert_helper.to_int0(web_helper.get_form('parent_id', '父id', is_check_null=False))14     sort = convert_helper.to_int0(web_helper.get_form('sort', '排序', is_check_null=False))15     is_leaf = web_helper.get_form('is_leaf', '是否最终节点', is_check_null=False)16     is_show = web_helper.get_form('is_show', '是否显示', is_check_null=False)17     is_enabled = web_helper.get_form('is_enabled', '是否启用', is_check_null=False)18 19     _menu_info_logic = menu_info_logic.MenuInfoLogic()20     # 如果没有设置排序,则自动获取当前级别最大的序号加121     if sort == 0:22         sort = _menu_info_logic.get_max('parent_id', 'parent_id='   str(parent_id))   123 24     # 组合更新字段25     fields = {26         'name': string,27         'icon': string,28         'page_url': string,29         'interface_url': string(interface_url),30         'sort': sort,31         'is_leaf': is_leaf,32         'is_show': is_show,33         'is_enabled': is_enabled,34     }35     # 修改记录36     result = _menu_info_logic.edit_model(id, fields)37     if result:38         return web_helper.return_msg(0, '提交成功')39     else:40         return web_helper.return_msg(-1, "提交失败")

图片 14

  为了方便管理,我们在api文件中创建system文件夹,用来存放所有后台权限管理功能的代码,并创建menu_info.py文件,来存放菜单管理接口

  前端菜单新增页面(menu_info_edit.html)大家下载源码包查看

  页面展示效果

  完成这些之后,我们还需要改造一下管理主界面左栏的菜单列表,改为从菜单管理数据表中读取方式

  为了让后台菜单好看一些,我们可以增加菜单小图标,H-ui框架中,提供了字体图标,这里的查看增加链接到官网中,可以直接查询字体图标编码复制过来使用

本文由彩世界开奖app官网发布于计算机编程,转载请注明出处:自家的率先个python web开辟框架(36卡塔 尔(阿拉

关键词: 框架 后台 第一个