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实现的数据结构与算法之队列详解
Apr 22 Python
浅谈python新手中常见的疑惑及解答
Jun 14 Python
在python的类中动态添加属性与生成对象
Sep 17 Python
Python创建xml文件示例
Mar 22 Python
python运行其他程序的实现方法
Jul 14 Python
Python实现针对json中某个关键字段进行排序操作示例
Dec 25 Python
Pycharm 设置默认头的图文教程
Jan 17 Python
使用opencv将视频帧转成图片输出
Dec 10 Python
python文件绝对路径写法介绍(windows)
Dec 25 Python
python中urllib.request和requests的使用及区别详解
May 05 Python
浅谈keras中的Merge层(实现层的相加、相减、相乘实例)
May 23 Python
python 实现图像快速替换某种颜色
Jun 04 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输出xml格式字符串(用的这个)
2012/07/12 PHP
解析php中memcache的应用
2013/06/18 PHP
PHP CURL CURLOPT参数说明(curl_setopt)
2013/09/30 PHP
Zend Framework教程之路由功能Zend_Controller_Router详解
2016/03/07 PHP
checkbox 复选框不能为空
2009/07/11 Javascript
设置iframe的document.designMode后仅Firefox中其body.innerHTML为br
2012/02/27 Javascript
Javascript基础教程之关键字和保留字汇总
2015/01/18 Javascript
基于jquery ui的alert,confirm方案(支持换肤)
2015/04/03 Javascript
JS拖拽组件学习使用
2016/01/19 Javascript
js 弹出对话框(遮罩)透明,可拖动的简单实例
2016/07/11 Javascript
浅谈JS运算符&&和|| 及其优先级
2016/08/10 Javascript
JS验证图片格式和大小并预览的简单实例
2016/10/11 Javascript
AngularJS用户选择器指令实例分析
2016/11/04 Javascript
聊聊JavaScript如何实现继承及特点
2017/04/07 Javascript
react高阶组件经典应用之权限控制详解
2017/09/07 Javascript
vue src动态加载请求获取图片的方法
2018/10/17 Javascript
mpvue实现小程序签到金币掉落动画(api实现)
2019/10/17 Javascript
VUE-ElementUI 自定义Loading图操作
2020/11/11 Javascript
Map与WeakMap类型在JavaScript中的使用详解
2020/11/18 Javascript
Python计算一个文件里字数的方法
2015/06/15 Python
11月编程语言排行榜 Python逆袭C#上升到第4
2017/11/15 Python
Python实现针对给定字符串寻找最长非重复子串的方法
2018/04/21 Python
Python读取指定日期邮件的实例
2019/02/01 Python
django基于restframework的CBV封装详解
2019/08/08 Python
Python 面向对象之封装、继承、多态操作实例分析
2019/11/21 Python
python判断两个序列的成员是否一样的实例代码
2020/03/01 Python
Perfume’s Club意大利官网:欧洲美妆电商
2019/05/03 全球购物
孝老爱亲模范事迹材料
2014/05/25 职场文书
事业单位人员的自我评价范文
2014/09/21 职场文书
2014年社区工会工作总结
2014/12/18 职场文书
简单的辞职信模板
2015/05/12 职场文书
党支部综合考察意见
2015/06/01 职场文书
当你找不到方向的时候,不妨读读刘备的一生
2019/08/05 职场文书
python中print格式化输出的问题
2021/04/16 Python
python基础之停用词过滤详解
2021/04/21 Python
纯CSS实现一个简单步骤条的示例代码
2022/07/15 HTML / CSS