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中global与nonlocal比较
Nov 21 Python
python通过定义一个类实例作为ftp回调方法
May 04 Python
Python比较2个时间大小的实现方法
Apr 10 Python
mac安装pytorch及系统的numpy更新方法
Jul 26 Python
Python读取excel中的图片完美解决方法
Jul 27 Python
django从请求到响应的过程深入讲解
Aug 01 Python
Python3 批量扫描端口的例子
Jul 25 Python
python实现ip地址查询经纬度定位详解
Aug 30 Python
Python3将jpg转为pdf文件的方法示例
Dec 13 Python
利用Python实现斐波那契数列的方法实例
Jul 26 Python
Python 如何创建一个简单的REST接口
Jul 30 Python
使用Django的JsonResponse返回数据的实现
Jan 15 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获取从百度搜索进入网站的关键词的详细代码
2014/01/08 PHP
PHP获取短链接跳转后的真实地址和响应头信息的方法
2014/07/25 PHP
php实现兼容2038年后Unix时间戳转换函数
2015/03/18 PHP
解读PHP中上传文件的处理问题
2016/05/29 PHP
js获取div高度的代码
2008/08/09 Javascript
JQuery与JSon实现的无刷新分页代码
2011/09/13 Javascript
JavaScript框架是什么?怎样才能叫做框架?
2015/07/01 Javascript
如何动态加载外部Javascript文件
2015/12/02 Javascript
基于BootStrap Metronic开发框架经验小结【一】框架总览及菜单模块的处理
2016/05/12 Javascript
jQuery实现的图片轮播效果完整示例
2016/09/12 Javascript
JS查找英文文章中出现频率最高的单词
2017/03/20 Javascript
JS基于正则表达式实现的密码强度验证功能示例
2017/09/21 Javascript
bootstrap时间插件daterangepicker使用详解
2017/10/19 Javascript
vue 优化CDN加速的方法示例
2018/09/19 Javascript
vue-cli项目中使用echarts图表实例
2018/10/22 Javascript
支付宝小程序tabbar底部导航
2018/11/06 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
2019/11/01 jQuery
[49:58]完美世界DOTA2联赛PWL S3 Magma vs DLG 第一场 12.18
2020/12/19 DOTA
python抓取网页图片并放到指定文件夹
2014/04/24 Python
python 筛选数据集中列中value长度大于20的数据集方法
2018/06/14 Python
Sanic框架Cookies操作示例
2018/07/17 Python
详解Python给照片换底色(蓝底换红底)
2019/03/22 Python
Python实现搜索算法的实例代码
2020/01/02 Python
Python3自定义http/https请求拦截mitmproxy脚本实例
2020/05/11 Python
Python语言编写智力问答小游戏功能
2020/10/13 Python
如何用python爬取微博热搜数据并保存
2021/02/20 Python
美国南部最大的家族百货公司:Belk
2017/01/30 全球购物
英国翻新电子产品购物网站:Tech Trade
2017/12/25 全球购物
全球异乡人的跨境社交电商平台:Kouhigh口嗨网
2020/07/24 全球购物
房产公证书范本
2014/04/10 职场文书
镇创先争优活动总结
2014/08/28 职场文书
中秋节国旗下演讲稿
2014/09/05 职场文书
解除劳动合同协议书
2014/09/17 职场文书
公司人力资源管理制度
2015/08/05 职场文书
详细总结Python常见的安全问题
2021/05/21 Python
Java面试题冲刺第十六天--消息队列
2021/08/07 面试题