首先分析一下树状结构,树状结构由多个互相关联的节点组成,所以需要一个节点类,
节点类里面字段必须与菜单表里面的必要字段一样
class TreeMenuNode:
"""树形菜单节点"""
def __init__(self, pk, title, code, icon_class, url, order, child, parent):
self.pk = pk
self.title = title
self.code = code
self.icon_class = icon_class
self.url = url
self.order = order
self.child = child
self.parent = parent
def count(self):
if not self.child:
return 0
return len(self.child)
class HandleTreeMenu:
"""处理树形侧边栏菜单"""
def __init__(self, menus):
self.menus = menus
self.tree_menu = []
def __iter__(self):
if self.tree_menu:
return iter(self.tree_menu)
return iter([])
@staticmethod
def get_complete_menu_structure(_menu_list):
"""得到完整的菜单结构"""
menu_list = copy.copy(_menu_list)
for menu in menu_list:
if menu.parent and menu.parent not in menu_list:
menu_list.append(menu.parent)
menu_list.extend(HandleTreeMenu.get_complete_menu_structure(menu_list))
return menu_list
def convert_to_tree(self):
"""转换BaseQuery为MenuTree结构"""
complete_menu = HandleTreeMenu.get_complete_menu_structure(self.menus)
top_menu = [menu for menu in complete_menu if not menu.parent]
for menu in top_menu:
current_menu = TreeMenuNode(menu.pk, menu.title, menu.code, menu.icon_class, menu.url, menu.order, [], None)
current_menu = self._recursive_menu(menu, current_menu)
self.tree_menu.append(current_menu)
def _recursive_menu(self, base_menu, base_tree_menu):
"""由上往下递归菜单得到所有菜单并转换为TreeMenuNode格式"""
complete_menu = HandleTreeMenu.get_complete_menu_structure(self.menus)
child_menu = [menu for menu in complete_menu if menu.parent == base_menu]
for menu in child_menu:
current_menu = TreeMenuNode(menu.pk, menu.title, menu.code, menu.icon_class, menu.url, menu.order, [], base_tree_menu)
current_menu = self._recursive_menu(menu, current_menu)
base_tree_menu.child.append(current_menu)
return base_tree_menu
class Menu(BaseModel):
"""侧边栏菜单模型"""
JK__model_name = '菜单'
pk = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False, comment='菜单标题')
code = db.Column(db.String, nullable=False, comment='权限代码')
icon_class = db.Column(db.String, nullable=True, comment='图标类')
url = db.Column(db.String, nullable=True, comment='链接地址')
order = db.Column(db.Integer, default=0, comment='排列顺序')
child_pk = db.Column(db.Integer, db.ForeignKey('menu.pk'))
parent = db.relationship(
'Menu',
remote_side=[pk],
backref=backref('child', lazy='dynamic'),
def __init__(self, title, code, icon_class, url, order):
self.title = title
self.code = code
self.icon_class = icon_class
self.url = url
self.order = order
if main == '__main__':
menus = Person.menu.all()
tree_menu = HandleTreeMenu(menus)
tree_menu.convert_to_tree()
print(tree_menu.tree_menu)
首先Sqlalchemy是不可以直接读取出有条件限制的树形结构菜单。只能自己实现一个上代码# 菜单表class Menu(BaseModel): """侧边栏菜单模型""" JK__model_name = '菜单' pk = db.Column(db.Integer, primary_key=True) title = db.Column(db.String, nullable=False, comment='菜单标题') code = db.Colu
安装Mysql-Python (这个是py的mysql驱动,这个在官方没有win的支持,只有第三方才有py2.7的whl)
pip install MySQL_python-1.2.5-cp27-none-win_amd64.whl
注:上述whl文件也可点击此处链接下载到本地安装:https://www.lfd.uci.edu/~gohlke/pythonlibs/
安装 Flask-SQLAlchemy
使用Flask-SQLAlchemy管理数据库
Flask-SQLAlchemy是一个Flask扩展,它简化了在Flask应用程序中对SQLAlchemy的使用。SQLAlchemy是一个强大的关系数据库框架,支持一些数据库后端。提供高级的ORM和底层访问数据库的本地SQL功能。
和其他扩展一样,通过pip安装Flask-SQLAlchemy:
(venv) $ pip install flask-sqlalchemy
在Flask-SQLAlchemy,数据库被指定为URL。表格列出三个最受欢迎的数据库引擎url的格式:
在这些URL中,hostname是指托管MySQL服务的服务
基于SQLAlcemy ORM库,利用左右值原理来实现树状存储的库。
什么是左右值树存储原理可以问度娘。
SATree可以在一张数据库表中存储多棵树,并可以方便地进行树的增加、删除、移动、输出等。
树的一个节点在存储为一条记录,表现为SQLALchemy一个混合了TreeMixin的Model实例。
通过pip进行安装
pip install satree
直接下载源代码,导入就可以使用
from satree imoport TreeMixin,TreeManager
SAtree只有一个源文件,直接导入就可以工作。
from satree imoport TreeMixin,TreeManager
将TreeMixin混合到SQLAlchemy Model中
engine = create_engine
需求场景:
使用sqlalchmy从现有的表中获取数据(不是自己建表)。百度了一下,网上都是使用sqlalchemy自己先创建表,然后导入数据表的模型类进行增删改查;现在不是自己建表,该如何操作呢?
通过sqlalchmey执行原生的sql语句,增删改查的原生语句携带表名,就不需要导入数据表的模型类了。
使用的包:
SQLAlchemy (1.3.10) + mysql-connector-python (8.0.19)
提供以下干货:
演示了向原生sql语句传递变量的用法 即动态执行sql语句 更加灵活
通过执行原生的sql语句实现操作已有的表
演示了sql语句根
这几天用户提出来一个这样的需求,要看上次系统上线的时候和这次要上线的系统的的菜单做一下对比,找出来那些的是新增的。而且要把路径写出来!
我一想这个比较简单,直接查查菜单, 给他统计一下不就OK了,但是我点了点,傻眼了,我们的菜单有好几百个,两个系统加起来有一千多,这么多我咋统计啊,我承认我是一个比较懒的人。不想去一个一个的查,所有只能想办法了。
因为我们的菜单都是
开发中经常会遇到树形结构的场景,比如:导航菜单、组织机构等等,但凡是有这种父子层级结构的都是如此,一级类目、二级类目、三级类目。。。
对于这种树形结构的表要如何设计呢?接下来一起探讨一下
首先,想一个问题,用非关系型数据库存储可不可以?
答案是肯定可以的,比如用mongoDB,直接将整棵树存成json。但是,这样不利于按条件查询,当然也取决于具体的需求,抛开需求谈设计都是耍流氓。
在菜单这个场景下,一般还是用关系型数据库存储,可以将最终的查询结构缓存起来。
常用的方法有四种:
sqlalchemy_mptt
无限极分类是一种比较常见的数据格式,生成组织结构,生成商品分类信息,权限管理当中的细节权限设置,都离不开无限极分类的管理。常见的有链表式,即有一个Pid指向上级的ID,以此来设置结构。写的时候简单,用的时候效果一班,比如说,同一级没有办法手动重新排序,查询所有子孙的时候不方便。 所以有了预排序树,它是修改后的前序遍历,即左右值树形管理。
树形结构图:
优点:可以快速确定关系,最短路径,同级排序,查找所有子孙(最好的地方)
pip install sqlalc