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 相关文章推荐
Python3实现从指定路径查找文件的方法
May 22 Python
python中文分词教程之前向最大正向匹配算法详解
Nov 02 Python
Django学习笔记之ORM基础教程
Mar 27 Python
Django使用HttpResponse返回图片并显示的方法
May 22 Python
python networkx 包绘制复杂网络关系图的实现
Jul 10 Python
详解Django模版中加载静态文件配置方法
Jul 21 Python
简单了解python filter、map、reduce的区别
Jan 14 Python
Python Selenium 设置元素等待的三种方式
Mar 18 Python
如何理解Python中包的引入
May 29 Python
Python读写压缩文件的方法
Jul 30 Python
Django实现文章详情页面跳转代码实例
Sep 16 Python
scrapy redis配置文件setting参数详解
Nov 18 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/02/06 PHP
CodeIgniter图像处理类的深入解析
2013/06/17 PHP
php+Memcached实现简单留言板功能示例
2017/02/15 PHP
PHP设计模式之委托模式定义与用法简单示例
2018/08/13 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
onpropertypchange
2006/07/01 Javascript
javascript 鼠标滚轮事件
2009/04/09 Javascript
Javascript验证上传图片大小[前台处理]
2014/07/18 Javascript
javascript修改图片src的方法
2015/01/27 Javascript
js使用onmousemove和onmouseout获取鼠标坐标的方法
2015/03/31 Javascript
javascript实现dom动态创建省市纵向列表菜单的方法
2015/05/14 Javascript
C++中的string类的用法小结
2015/08/07 Javascript
JS快速实现移动端拼图游戏
2016/09/05 Javascript
angular实现表单验证及提交功能
2017/02/01 Javascript
nodejs入门教程二:创建一个简单应用示例
2017/04/24 NodeJs
JavaScript设计模式之职责链模式应用示例
2018/08/07 Javascript
JavaScript引用类型RegExp基本用法详解
2018/08/09 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
2018/12/24 Javascript
Vue.js如何使用Socket.IO的示例代码
2019/09/05 Javascript
一个检测OpenSSL心脏出血漏洞的Python脚本分享
2014/04/10 Python
浅谈Python数据类型之间的转换
2016/06/08 Python
Python实现多属性排序的方法
2018/12/05 Python
Python实现二叉搜索树BST的方法示例
2019/07/30 Python
python区分不同数据类型的方法
2019/10/14 Python
Python Mock模块原理及使用方法详解
2020/07/07 Python
酒店管理自荐信
2013/10/23 职场文书
物流专业大学生求职信范文
2013/10/28 职场文书
书法培训心得体会
2014/01/05 职场文书
学雷锋月活动总结
2014/04/25 职场文书
祖国在我心中演讲稿300字
2014/05/04 职场文书
幼师求职自荐信
2014/05/31 职场文书
员工安全责任书范本
2014/07/24 职场文书
2015年教师党员公开承诺书
2015/01/22 职场文书
借条格式范本
2015/05/25 职场文书
CSS中em的正确打开方式详解
2021/04/08 HTML / CSS
MySQL获取所有分类的前N条记录
2021/05/07 MySQL