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实现并发检验代理池地址的方法
Sep 18 Python
TF-IDF与余弦相似性的应用(二) 找出相似文章
Dec 21 Python
用pandas中的DataFrame时选取行或列的方法
Jul 11 Python
Python GUI编程 文本弹窗的实例
Jun 11 Python
浅谈Python2之汉字编码为unicode的问题(即类似\xc3\xa4)
Aug 12 Python
Django stark组件使用及原理详解
Aug 22 Python
python单向链表的基本实现与使用方法【定义、遍历、添加、删除、查找等】
Oct 24 Python
pip install 使用国内镜像的方法示例
Apr 03 Python
Keras 快速解决OOM超内存的问题
Jun 11 Python
浅谈Python数学建模之线性规划
Jun 23 Python
Python面向对象编程之类的概念
Nov 01 Python
python实现手机推送 代码也就10行左右
Apr 12 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
10条PHP编程习惯助你找工作
2008/09/29 PHP
php中注册器模式类用法实例分析
2015/11/03 PHP
PHP几个实用自定义函数小结
2016/01/25 PHP
php基于curl实现随机ip地址抓取内容的方法
2016/10/11 PHP
jQuery 学习第七课 扩展jQuery的功能 插件开发
2010/05/17 Javascript
封装html的select标签的js操作实例
2013/07/02 Javascript
jquery实现更改表格行顺序示例
2014/04/30 Javascript
JS的encodeURI和java的URLDecoder.decode使用介绍
2014/05/08 Javascript
angularjs实现与服务器交互分享
2014/06/24 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
jquery实现聚光灯效果的方法
2015/02/06 Javascript
jQuery Dialog 取消右上角删除按钮事件
2016/09/07 Javascript
Angular使用ng-messages与PHP进行表单数据验证
2016/12/28 Javascript
js实现百度搜索提示框
2017/02/05 Javascript
详解react如何在组件中获取路由参数
2017/06/15 Javascript
JavaScript正则表达式简单实用实例
2017/06/23 Javascript
动手写一个angular版本的Message组件的方法
2017/12/16 Javascript
微信小程序页面生命周期详解
2018/01/31 Javascript
Vue数据双向绑定原理及简单实现方法
2018/05/18 Javascript
[46:03]LGD vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python实现嵌套列表去重方法示例
2017/12/28 Python
Windows下安装Django框架的方法简明教程
2018/03/28 Python
Python实现的堆排序算法示例
2018/04/29 Python
Python3中lambda表达式与函数式编程讲解
2019/01/14 Python
Python使用字典实现的简单记事本功能示例
2019/08/15 Python
Python Subprocess模块原理及实例
2019/08/26 Python
sqlalchemy实现时间列自动更新教程
2020/09/02 Python
使用python画出逻辑斯蒂映射(logistic map)中的分叉图案例
2020/12/11 Python
亿企通软件测试面试题
2012/04/10 面试题
城市轨道交通工程职业规划书范文
2014/01/18 职场文书
推广普通话演讲稿
2014/05/23 职场文书
应届毕业生自荐书
2014/06/18 职场文书
同学会感言
2015/07/30 职场文书
Java tomcat手动配置servlet详解
2021/11/27 Java/Android
Redis基本数据类型List常用操作命令
2022/06/01 Redis
win11怎么消除图标小盾牌?win11消除图标小盾牌解决方法
2022/08/05 数码科技