class MenuHelper(object):
def __init__(self,request,username):
#当前请求的request
self.request=request
#当前用户名
self.username=username
#获取当前url
self.current_url=request.path_info
#获取当前用户的所有权限
self.permission2action_dict= {} #{'url':["操作列表"],}
#菜单的叶子节点,即:菜单的最后一层应该(含有权限url)显示的权限,对应上面的permission2action_dict
self.menu_leaf_list=[]
#获取所有菜单对象
self.menu_list=[]#初始化数据,将数据放入session中
self.session_data()
#注:只进行数据处理(数据最后是基础类型),不进行业务逻辑(目标就是将数据放在session中)
def session_data(self):
#(0)先在session中查看数据是否已经存在
permission_dict= self.request.session.get("permission_info")ifpermission_dict:
self.permission2action_dict= permission_dict['permission2action_dict']
self.menu_leaf_list= permission_dict['menu_leaf_list']
self.menu_list= permission_dict['menu_list']return#获取所有角色
r_list= models.Role.objects.filter(user2role__u__username=self.username).all()
#获取角色下的所有权限操作,存放方式{'url':["操作列表"],}便于查找 --> 例如 {'user.html':['get','post'],}
p2a_list= models.Permission2Action.objects.filter(permission2action2role__r__in=r_list)
#权限操作去重,使用集合去重
p2a_list= set(p2a_list)
#(1)循环权限操作列表,将其变为{'user.html':['get','post'],}格式,然后加入self.permission2action_dictfor p2a inp2a_list:
# print(p2a.p.url)if self.permission2action_dict.get(p2a.p.url) ==None:
self.permission2action_dict[p2a.p.url]=[]
self.permission2action_dict[p2a.p.url].append(p2a.a.code)
#上面是用户拥有的所有权限,用于权限校验,下面这个是显示在菜单最后一层的权限(也只有最后一层才会有url权限)
#(2)获取菜单的叶子节点,即:菜单的最后一层应该显示的权限
self.menu_leaf_list=list(
models.Permission2Action.objects. \
filter(permission2action2role__r__in=r_list).exclude(p__menu__isnull=True). \
values('p_id','p__url','p__caption','p__menu').distinct()
)
#(3)获取所有的菜单全部,(根据上面的菜单叶子节点,以及下面的所有菜单,进行比较,我们可以获取到所有应该显示的菜单)
self.menu_list= list(models.Menu.objects.values('id','caption','parent_id'))
#(4)将上面获取的数据,放入session中
self.request.session['permission_info'] ={'permission2action_dict':self.permission2action_dict,'menu_leaf_list':self.menu_leaf_list,'menu_list':self.menu_list,
}
#生成菜单树形结构(包括其他数据)
def menu_data_list(self):
menu_leaf_dict={}
#形式
# {
#'父id':['子节点','子节点',],
#'父id':['子节点','子节点',]
# }
open_leaf_parent_id=None
#(1)归并所有叶子节点for item inself.menu_leaf_list:
item={'id':item['p_id'],'url':item['p__url'],'caption':item['p__caption'],'parent_id':item['p__menu'], #对应的是菜单id,可以看出,每个叶子节点都是挂在菜单节点下面,我们只需获取菜单的树形结构,将权限叶子节点挂载上去就可以'child':[],'status':True, #是否显示'open':False #是否展开
}if item['parent_id'] inmenu_leaf_dict:
menu_leaf_dict[item['parent_id']].append(item)else:
menu_leaf_dict[item['parent_id']] =[item,]if re.match(item['url'],self.current_url): #若是当前访问的url,则打开
item['open'] =True
open_leaf_parent_id= item['parent_id']
#(2)获取所有菜单字典
menu_dict={}
#形式也是
# {
#'菜单id':'对应数据处理的字典',
#'菜单id': '对应数据处理的字典',
#'菜单id': '对应数据处理的字典',
# }for item inself.menu_list:
item['child'] =[]
item['status'] =False #是否显示,只有拥有权限的菜单,才会展示给用户,其他的不会显示
item['open'] =False #和权限叶子节点一致,展开就是一级一级显示,其他闭合
menu_dict[item['id']] =item
#根据上面的全部菜单和归并后的叶子节点一起获取我们真正需要的菜单
#(3)将叶子节点添加到菜单中for k,v inmenu_leaf_dict.items():
menu_dict[k]['child'] =v #为菜单挂载上权限叶子节点
parent_id=kwhileparent_id: #当权限子节点存在,则其父级会向上全部显示
menu_dict[parent_id]['status'] =True
parent_id= menu_dict[parent_id]['parent_id']
#(4)将菜单中已经选中的菜单标记为展开(一级一级展开)whileopen_leaf_parent_id:
menu_dict[open_leaf_parent_id]['open'] =True
open_leaf_parent_id= menu_dict[open_leaf_parent_id]['parent_id']
#(5)对所有菜单,进行树形结构生成,不需要考虑其他的因素(例如是否是叶子节点,是否有权限)
#我们只需要判断状态status是否为True,然后筛选即可
result=[]for row inmenu_dict.values(): #所有菜单进行树形排序if not row['parent_id']:
result.append(row) # 注意:基础-->列表赋值的时候默认是浅拷贝,所以无论是是么时候添加到result中,后面的操作对于result数据也是有效d的else:
menu_dict[row['parent_id']]['child'].append(row)
#(6)返回树形结构returnresult
#获取子菜单列表的子菜单列表(递归模式)
def menu_content(self,child_list):
response= ""# 菜单模板HTML
tpl= """
""" for row inchild_list:if not row['status']:continueactive= ""
if row['open']:
active= "active"
if 'url' inrow:
response+= "%s"%(active,row['url'],row['caption'])else:
title= row['caption']
content= self.menu_content(row['child'])
response+= tpl %(active,title,content)returnresponse
def menu_tree(self):
response= ""# 菜单模板HTML
tpl= """
"""
for row inself.menu_data_list(): #获取函数返回的树形结构,进行HTML处理,这里全是根目录菜单if not row['status']: #对于不需要显示的,不做处理continueactive= ""
if row['open']: #对于展开的,我们要设置其状态为active
active= "active"title= row['caption']
#获取其子代的HTML,放在content中
content= self.menu_content(row['child']) #默认子代是列表
response+= tpl %(active,title,content)returnresponse
def actions(self):'''检测当前用户是否对当前url有权限访问,并获取对当前url有什么权限
:return:''' action_list =[]
#当前数据中保存的权限是{'user.html':['get','post'],}格式,在self.permission2action_dict中for k,v inself.permission2action_dict.items():ifre.match(k,self.current_url):
action_list=vbreak
return action_list