python递归查询菜单并转换成json实例


Posted in Python onMarch 27, 2017

最近需要用python写一个菜单,折腾了两三天才搞定,现在记录在此,需要的朋友可以借鉴一下。

备注:文章引用非可执行完整代码,仅仅摘录了关键部分的代码

环境

  • 数据库:mysql
  • python:3.6

表结构

CREATE TABLE `tb_menu` (
 `id` varchar(32) NOT NULL COMMENT '唯一标识',
 `menu_name` varchar(40) DEFAULT NULL COMMENT '菜单名称',
 `menu_url` varchar(100) DEFAULT NULL COMMENT '菜单链接',
 `type` varchar(1) DEFAULT NULL COMMENT '类型',
 `parent` varchar(32) DEFAULT NULL COMMENT '父级目录id',
 `del_flag` varchar(1) NOT NULL DEFAULT '0' COMMENT '删除标志 0:不删除 1:已删除',
 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
 `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单表';

Python代码

Menu对象中,有一个子菜单列表的引用“subMenus”,类型为list

核心代码

def set_subMenus(id, menus):
  """
  根据传递过来的父菜单id,递归设置各层次父菜单的子菜单列表

  :param id: 父级id
  :param menus: 子菜单列表
  :return: 如果这个菜单没有子菜单,返回None;如果有子菜单,返回子菜单列表
  """
  # 记录子菜单列表
  subMenus = []
  # 遍历子菜单
  for m in menus:
    if m.parent == id:
      subMenus.append(m)

  # 把子菜单的子菜单再循环一遍
  for sub in subMenus:
    menus2 = queryByParent(sub.id)
    # 还有子菜单
    if len(menus):
      sub.subMenus = set_subMenus(sub.id, menus2)

  # 子菜单列表不为空
  if len(subMenus):
    return subMenus
  else: # 没有子菜单了
    return None

测试方法

def test_set_subMenus(self):
    # 一级菜单
    rootMenus = queryByParent('')
    for menu in rootMenus:
      subMenus = queryByParent(menu.id)
      menu.subMenus = set_subMenus(menu.id, subMenus)

备注:基本流程是:先查询一级菜单,然后分别把该级菜单的id、和这级菜单的子菜单列表传入set_subMenus方法,递归进行子菜单列表的下级菜单设置;

支持传递菜单Id,查询该菜单下面的所有子菜单。传递空字符,则从根目录开始查询

在“rootMenus ”对象中,可以看到完整的菜单树形结构

转Json

我采用的ORM框架是:sqlalchemy,直接从数据库中查询出来的Menu对象,转Json时会报错。需要重新定义一个DTO类,来把Menu对象转成Dto对象。

MenuDto

class MenuDto():
  def __init__(self, id, menu_name, menu_url, type, parent, subMenus):
    super().__init__()
    self.id = id
    self.menu_name = menu_name
    self.menu_url = menu_url
    self.type = type
    self.parent = parent
    self.subMenus = subMenus

  def __str__(self):
    return '%s(id=%s,menu_name=%s,menu_url=%s,type=%s,parent=%s)' % (
      self.__class__.__name__, self.id, self.menu_name, self.menu_url, self.type, self.parent)

  __repr = __str__

于是,重新定义了递归设置子菜单的方法

def set_subMenuDtos(id, menuDtos):
  """
  根据传递过来的父菜单id,递归设置各层次父菜单的子菜单列表

  :param id: 父级id
  :param menuDtos: 子菜单列表
  :return: 如果这个菜单没有子菜单,返回None;如果有子菜单,返回子菜单列表
  """
  # 记录子菜单列表
  subMenuDtos = []
  # 遍历子菜单
  for m in menuDtos:
    m.name = to_pinyin(m.menu_name)
    if m.parent == id:
      subMenuDtos.append(m)

  # 把子菜单的子菜单再循环一遍
  for sub in subMenuDtos:
    menus2 = queryByParent(sub.id)
    menusDto2 = model_list_2_dto_list(menus2,
                     "MenuDto(id='', menu_name='', menu_url='', type='', parent='', subMenus='')")
    # 还有子菜单
    if len(menuDtos):
      if len(menusDto2):
        sub.subMenus = set_subMenuDtos(sub.id, menusDto2)
      else: # 没有子菜单,删除该节点
        sub.__delattr__('subMenus')

  # 子菜单列表不为空
  if len(subMenuDtos):
    return subMenuDtos
  else: # 没有子菜单了
    return None

备注:

  1. 当一个菜单没有子菜单时,删除掉“subMenus”属性,否则转Json时会出现空值
  2. model_list_2_dto_list 方法可以把Menu列表转成MenuDto列表
  3. to_pinyin 是把汉字转成拼音的方法,在这里不用关注

View层返回Json的方法

def get(self):
    param = request.args
    id = param['id']
    # 如果id为空,查询的是从根目录开始的各级菜单
    rootMenus = queryByParent(id)
    rootMenuDtos = model_list_2_dto_list(rootMenus,
                       "MenuDto(id='', menu_name='', menu_url='', type='', parent='', subMenus='')")
    # 设置各级子菜单
    for menu in rootMenuDtos:
      menu.name = to_pinyin(menu.menu_name)
      subMenus = queryByParent(menu.id)
      if len(subMenus):
        subMenuDtos = model_list_2_dto_list(subMenus,
                          "MenuDto(id='', menu_name='', menu_url='', type='', parent='', subMenus='')")
        menu.subMenus = set_subMenuDtos(menu.id, subMenuDtos)
      else:
        menu.__delattr__('subMenus')

    menus_json = json.dumps(rootMenuDtos, default=lambda o: o.__dict__, sort_keys=True, allow_nan=false,
                skipkeys=true)
    # 需要转字典,否则返回的字符串会带有“\”
    menus_dict = json_dict(menus_json)
    return fullResponse(menus_dict)
fullResponse

from flask import jsonify


def fullResponse(data='', msg='', code=0):
  if msg == '':
    return jsonify({'code': code, 'data': data})
  elif data == '':
    return jsonify({'code': code, 'msg': msg})
  else:
    return jsonify({'code': code, 'msg': msg, 'data': data})

备注:python中json和字典的含义类似,在最后json返回给页面时,需要先使用json_dict方法转成dict类型,否则返回的字符串中会带有“\”

查询结果

python递归查询菜单并转换成json实例

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python anaconda 安装 环境变量 升级 以及特殊库安装的方法
Jun 21 Python
django创建自定义模板处理器的实例详解
Aug 14 Python
python3库numpy数组属性的查看方法
Apr 17 Python
Python装饰器简单用法实例小结
Dec 03 Python
对python3 中方法各种参数和返回值详解
Dec 15 Python
初探利用Python进行图文识别(OCR)
Feb 26 Python
在win10和linux上分别安装Python虚拟环境的方法步骤
May 09 Python
Python3内置模块pprint让打印比print更美观详解
Jun 02 Python
Python中zip函数如何使用
Jun 04 Python
利用Python实现字幕挂载(把字幕文件与视频合并)思路详解
Oct 21 Python
Python爬虫入门案例之回车桌面壁纸网美女图片采集
Oct 16 Python
python对文档中元素删除,替换操作
Apr 02 Python
Python中的命令行参数解析工具之docopt详解
Mar 27 #Python
Python使用PDFMiner解析PDF代码实例
Mar 27 #Python
详解python并发获取snmp信息及性能测试
Mar 27 #Python
使用Python写CUDA程序的方法
Mar 27 #Python
pyenv命令管理多个Python版本
Mar 26 #Python
Django实现自定义404,500页面教程
Mar 26 #Python
Python 多线程实例详解
Mar 25 #Python
You might like
php 字符过滤类,用于过滤各类用户输入的数据
2009/05/27 PHP
PHP实现获取域名的方法小结
2014/11/05 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
定位地理位置PHP判断员工打卡签到经纬度是否在打卡之内
2019/05/23 PHP
JavaScript:Div层拖动效果实例代码
2013/08/06 Javascript
开发插件的两个方法jquery.fn.extend与jquery.extend
2013/11/21 Javascript
javascript 对象数组根据对象object key的值排序
2015/03/09 Javascript
JavaScript学习笔记之DOM基础 2.4
2015/08/14 Javascript
浅谈javascript的call()、apply()、bind()的用法
2016/02/21 Javascript
Nodejs获取网络数据并生成Excel表格
2020/03/31 NodeJs
第九篇Bootstrap导航菜单创建步骤详解
2016/06/21 Javascript
bootstrap多种样式进度条展示
2016/12/20 Javascript
webpack配置的最佳实践分享
2017/04/21 Javascript
Angular5升级RxJS到5.5.3报错:EmptyError: no elements in sequence的解决方法
2018/04/09 Javascript
vue-resource请求实现http登录拦截或者路由拦截的方法
2018/07/11 Javascript
微信小程序自定义组件封装及父子间组件传值的方法
2018/08/28 Javascript
jQuery实现鼠标移入移出事件切换功能示例
2018/09/06 jQuery
JS监听滚动和id自动定位滚动
2018/12/18 Javascript
深入理解 JS 垃圾回收
2019/06/03 Javascript
JavaScript 实现轮播图特效的示例
2020/11/05 Javascript
[03:48]显微镜下的DOTA2第四期——TP动作
2014/06/20 DOTA
[59:30]完美世界DOTA2联赛PWL S3 access vs LBZS 第二场 12.20
2020/12/23 DOTA
Django返回json数据用法示例
2016/09/18 Python
详解python中的json的基本使用方法
2016/12/21 Python
Python离线安装PIL 模块的方法
2019/01/08 Python
Pytorch Tensor 输出为txt和mat格式方式
2020/01/03 Python
如何用Matplotlib 画三维图的示例代码
2020/07/28 Python
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
幼儿运动会邀请函
2014/01/17 职场文书
司机检讨书
2014/02/13 职场文书
小学母亲节活动方案
2014/03/14 职场文书
经济职业学院毕业生自荐书
2014/03/17 职场文书
幼儿园家长寄语
2014/04/02 职场文书
爱国演讲稿500字
2014/05/04 职场文书
银行主办会计岗位职责
2014/08/13 职场文书
解决Maven项目中 Invalid bound statement 无效的绑定问题
2021/06/15 Java/Android