左侧菜单即权限管理
管理系统
左侧菜单:
表关系
数据库
class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) class Meta: verbose_name_plural = '用户表' def __str__(self): return self.username #角色表 class Role(models.Model): caption = models.CharField(max_length=32)#角色 class Meta: verbose_name_plural = '角色表' def __str__(self): return self.caption #用户分配角色 class User2Role(models.Model): u = models.ForeignKey(User)#用户表 r = models.ForeignKey(Role)#角色表 class Meta: verbose_name_plural = '用户分配角色' def __str__(self): return "%s-%s" %(self.u.username,self.r.caption,) #操作表 class Action(models.Model): # get 获取用户信息1 # post 创建用户2 # delete 删除用户3 # put 修改用户4 caption = models.CharField(max_length=32)#标题 code = models.CharField(max_length=32)#操作 class Meta: verbose_name_plural = '操作表' def __str__(self): return self.caption #URL表 class Permission(models.Model): # http://127.0.0.1:8001/user.html 用户管理 1 # http://127.0.0.1:8001/order.html 订单管理 1 caption = models.CharField(max_length=32)#标题 url = models.CharField(max_length=32)#链接 menus=models.ForeignKey("Menus",null=True,blank=True) class Meta: verbose_name_plural = 'URL表' def __str__(self): return "%s-%s" %(self.caption,self.url,) class Menus(models.Model): caption=models.CharField(max_length=32) parent_id=models.ForeignKey("self",null=True,blank=True) class Meta: db_table="Menus" verbose_name_plural="菜单表" def __str__(self): return self.caption #权限表 class Permission2Action(models.Model): """ 1 1 1 2 1 3 1 4 2 2 """ p = models.ForeignKey(Permission)#url a = models.ForeignKey(Action)#增删改的请求 class Meta: verbose_name_plural = '权限表' def __str__(self): return "%s-%s:-%s?t=%s" %(self.p.caption,self.a.caption,self.p.url,self.a.code,) #角色分配权限 class Permission2Action2Role(models.Model): p2a = models.ForeignKey(Permission2Action)#权限表 r = models.ForeignKey(Role)#用户 class Meta: verbose_name_plural = '角色分配权限' def __str__(self): return "%s==>%s" %(self.r.caption,self.p2a,)
获取权限所需的值
#获取当前用户的所有角色列表 role_list=models.Role.objects.filter(user2role__u__username=self.username) #获取当前的权限列表{"p__url":url,"a__code":get} permission2action_list=models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).values("p__url","a__code").distinct() permission2action_dict={}#转换成{"url":get}的格式 for item in permission2action_list: if item["p__url"] in permission2action_dict: permission2action_dict[item["p__url"]]=item["a__code"] else: permission2action_dict[item["p__url"]]=["p__cole"] #获取菜单的叶子节点:即菜单的最后一层权限 menu_leaf_list=list(models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).exclude(p__menus__isnull=True).values("p_id","p__url","p__caption","p__menus").distinct()) #获取所有的菜单列表 menu_list=list(models.Menus.objects.values("id","caption","parent_id"))
生成菜单
menu_leaf_dict={} open_leaf_parent_id=None #归并所有的叶子节点 for item in self.menu_leaf_list: item = { 'id': item['p_id'], 'url': item['p__url'], 'caption': item['p__caption'], 'parent_id': item['p__menus'], 'child': [], 'status': True, # 是否显示 'open': False } #把列表变成字典,key是父级的id if item['parent_id'] in menu_leaf_dict:#把叶子节点同级的挂在一起,挂在父级id上 menu_leaf_dict[item['parent_id']].append(item) else: menu_leaf_dict[item['parent_id']] = [item, ] if re.match(item['url'], self.current_url):#是否是链接的叶子节点 item['open'] = True#有链接的叶子节点加一个状态等于True open_leaf_parent_id = item['parent_id']#重设标志位 # 获取所有菜单字典 menu_dict = {} for item in self.menu_list: #给每个菜单的字典设置初始状态 item['child'] = [] item['status'] = False item['open'] = False menu_dict[item['id']] = item#把列表变成字典key是自己的id # 讲叶子节点添加到菜单中 for k, v in menu_leaf_dict.items():#循环最里层的叶子节点,key是父级的id menu_dict[k]['child'] = v#在菜单字典中id是叶子节点的id,所有在菜单字典中child里可以把最底层的叶子挂上去 parent_id = k#k是叶子节点的父id,是菜单节点的id # 将后代中有叶子节点的菜单标记为【显示】通过while循环把一条线都标记 while parent_id: menu_dict[parent_id]['status'] = True#第一次是叶子节点的父id,当前菜单的id,在菜单把status的状态改成True parent_id = menu_dict[parent_id]['parent_id']#把当前的菜单的父id找到并赋值,每次就找到的父亲 # 将已经选中的菜单标记为【展开】 while open_leaf_parent_id:#等于True表示菜单中有链接,当前连接的一条线标记为True menu_dict[open_leaf_parent_id]['open'] = True open_leaf_parent_id = menu_dict[open_leaf_parent_id]['parent_id'] # 生成树形结构数据 result = []#用来放菜单根的 for row in menu_dict.values():#循环菜单字典 if not row['parent_id']:#判断是否是根 result.append(row) else: menu_dict[row['parent_id']]['child'].append(row)#row['parent_id']是父id, # 把当前菜单挂在父id的child列表里
#result是最后的结果
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% block css %} <style> .content{ margin-left: 20px; } .content a{ display: block; } .active{ color: red; } .content .title,a{ {# display: none;#} } .hide{ display: none; } </style> {% endblock %} </head> <body> {% block content %} <div style="float: left;width: 20%"> {{ menu_string |safe }} </div> <div style="float: left;width: 80%"> {% if "get" in action_list %} <a href="http://www.baidu.com">添加</a> {% endif %} </div> {% endblock %} <script src="/static/js/jquery-3.1.1.js"></script> <script> </script> </body> </html>
封装到类里面
左侧菜单简单版
from django.shortcuts import render,HttpResponse # Create your views here. from app01 import models class MenuHelper(object): def __init__(self,id,current_url): self.permission2action_list=None self.result=None self.id=id self.current_url=current_url self.init_data() def init_data(self): role_list=models.Role.objects.filter(user2role__u__id=self.id) permission2action_list=models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).values("p__url","a__code").distinct() self.permission2action_list=permission2action_list #这个人所得到的权限,可保存在session #所有角色在不在这个人的角色里 #必须是要和菜单有关联的不能是空的 menu_leaf_list=models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).exclude(p__menus__isnull=True).values("p_id","p__url","p__caption","p__menus").distinct() #取到的是最底成的链接 menu_leaf_dic={} open_leaf_parent_id=None for item in menu_leaf_list: item={ "id":item["p_id"], "url":item["p__url"], "caption":item["p__caption"], "parent_id":item["p__menus"], "child":[], "status":True, "open":False } #取出最底层的链接转换成字典 if item["parent_id"]in menu_leaf_dic: menu_leaf_dic[item["parent_id"]].append(item) else: menu_leaf_dic[item["parent_id"]]=[item,] #把链接上做一个挂在菜单上的钩子 import re if re.match(item["url"],self.current_url): item["open"]=True#有链接就改变状态 open_leaf_parent_id=item["parent_id"] menu_list=models.Menus.objects.values('id', 'caption', 'parent_id') menu_dict={} for item in menu_list: item["child"]=[] item["status"]=False item["open"]=False menu_dict[item["id"]]=item #取出所有放到字典里 for k,v in menu_leaf_dic.items(): menu_dict[k]["child"]=v#把链接放到菜单上了 parent_id=k while parent_id: #把有东西的菜单的状态变成True menu_dict[parent_id]["status"]=True parent_id=menu_dict[parent_id]["parent_id"] while open_leaf_parent_id: #把需要展开的菜单的状态改变为True menu_dict[open_leaf_parent_id]["open"]=True open_leaf_parent_id=menu_dict[open_leaf_parent_id]["parent_id"] result=[] for item in menu_dict.values(): if not item["parent_id"]: result.append(item) else: menu_dict[item["parent_id"]]["child"].append(item) self.result=result def menu_content(self,child_list): response="" tpl=""" <div class="item %s"> <div class="title">%s</div> <div class="content">%s</div> </div> """ for item in child_list: if not item["status"]: continue hide="" if item["open"]: hide="hide" if "url"in item: response += "<a class='%s' href='%s'>%s</a>" % (hide, item['url'], item['caption']) else: title=item["caption"] content=self.menu_content(item["child"]) response+=tpl%(hide,title,content) return response def menu_tree(self): response="" tpl=""" <div class="item %s"> <div class="title">%s</div> <div class="content">%s</div> </div> """ for item in self.result: if not item["status"]: continue hide="" if item["open"]: hide="hide" title=item["caption"] content=self.menu_content(item["child"]) response+=tpl%(hide,title,content) return response def login(request): # user_request_url = "/product.html" user_request_url = "/order.html" # user_request_url = "/girl.html" id=6 obj = MenuHelper(id, user_request_url) string = obj.menu_tree() return render(request,"index3.html",{"menu_string":string})
加上权限的左侧菜单
牛逼版
from django.shortcuts import render,HttpResponse,redirect # Create your views here. from app01 import models import re class MenuHelper(object): def __init__(self,request,username): self.request=request #当前请求的request对象 self.username=username #当前用户 self.current_url=request.path_info #当前url self.permission2action_dict=None #当前用户所有权限 self.menu_leaf_list=None #当前菜单中显示的权限 self.menu_list=None #当前所有菜单 self.session_data() def session_data(self): permission_dict=self.request.session.get("permission_info") if permission_dict: self.permission2action_dict=permission_dict["permission2action_dict"] self.menu_leaf_list=permission_dict["menu_leaf_list"] self.menu_list=permission_dict["menu_list"] else: #获取当前用户的所有角色列表 role_list=models.Role.objects.filter(user2role__u__username=self.username) #获取当前的权限列表{"p__url":url,"a__code":get} permission2action_list=models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).values("p__url","a__code").distinct() permission2action_dict={}#转换成{"url":get}的格式 for item in permission2action_list: if item["p__url"] in permission2action_dict: permission2action_dict[item["p__url"]]=item["a__code"] else: permission2action_dict[item["p__url"]]=["p__cole"] #获取菜单的叶子节点:即菜单的最后一层权限 menu_leaf_list=list(models.Permission2Action.objects.filter(permission2action2role__r__in=role_list).exclude(p__menus__isnull=True).values("p_id","p__url","p__caption","p__menus").distinct()) #获取所有的菜单列表 menu_list=list(models.Menus.objects.values("id","caption","parent_id")) self.request.session["permission_info"]={ "permission2action_dict":permission2action_dict, "menu_leaf_list":menu_leaf_list, "menu_list":menu_list } #放到session里 self.permission2action_dict=permission2action_dict self.menu_leaf_list=menu_leaf_list self.menu_list=menu_list def menu_data_list(self): menu_leaf_dict={} open_leaf_parent_id=None #归并所有的叶子节点 for item in self.menu_leaf_list: item = { 'id': item['p_id'], 'url': item['p__url'], 'caption': item['p__caption'], 'parent_id': item['p__menus'], 'child': [], 'status': True, # 是否显示 'open': False } #把列表变成字典,key是父级的id if item['parent_id'] in menu_leaf_dict:#把叶子节点同级的挂在一起,挂在父级id上 menu_leaf_dict[item['parent_id']].append(item) else: menu_leaf_dict[item['parent_id']] = [item, ] if re.match(item['url'], self.current_url):#是否是链接的叶子节点 item['open'] = True#有链接的叶子节点加一个状态等于True open_leaf_parent_id = item['parent_id']#重设标志位 # 获取所有菜单字典 menu_dict = {} for item in self.menu_list: #给每个菜单的字典设置初始状态 item['child'] = [] item['status'] = False item['open'] = False menu_dict[item['id']] = item#把列表变成字典key是自己的id # 讲叶子节点添加到菜单中 for k, v in menu_leaf_dict.items():#循环最里层的叶子节点,key是父级的id menu_dict[k]['child'] = v#在菜单字典中id是叶子节点的id,所有在菜单字典中child里可以把最底层的叶子挂上去 parent_id = k#k是叶子节点的父id,是菜单节点的id # 将后代中有叶子节点的菜单标记为【显示】通过while循环把一条线都标记 while parent_id: menu_dict[parent_id]['status'] = True#第一次是叶子节点的父id,当前菜单的id,在菜单把status的状态改成True parent_id = menu_dict[parent_id]['parent_id']#把当前的菜单的父id找到并赋值,每次就找到的父亲 # 将已经选中的菜单标记为【展开】 while open_leaf_parent_id:#等于True表示菜单中有链接,当前连接的一条线标记为True menu_dict[open_leaf_parent_id]['open'] = True open_leaf_parent_id = menu_dict[open_leaf_parent_id]['parent_id'] # 生成树形结构数据 result = []#用来放菜单根的 for row in menu_dict.values():#循环菜单字典 if not row['parent_id']:#判断是否是根 result.append(row) else: menu_dict[row['parent_id']]['child'].append(row)#row['parent_id']是父id, # 把当前菜单挂在父id的child列表里 return result#成型的大树 def menu_content(self,child_list): response="" tpl=""" <div class="item %s"> <div class="title">%s</div> <div class="content">%s</div> </div> """ for item in child_list: if not item["status"]: continue hide="" if item["open"]: hide="hide" if "url"in item: response += "<a class='%s' href='%s'>%s</a>" % (hide, item['url'], item['caption']) else: title=item["caption"] content=self.menu_content(item["child"]) response+=tpl%(hide,title,content) return response def menu_tree(self): response="" tpl=""" <div class="item %s"> <div class="title">%s</div> <div class="content">%s</div> </div> """ for item in self.menu_data_list(): if not item["status"]: continue hide="" if item["open"]: hide="hide" title=item["caption"] content=self.menu_content(item["child"]) response+=tpl%(hide,title,content) return response def actions(self): """ 检查用户是否对当前URL有访问权,并获取对当前URL有什么权限 :param request: :return: """ url_regex=None action_list=[] #当前所有权限 for k,v in self.permission2action_dict.items(): if re.match(k,self.current_url): url_regex=k action_list=v break return action_list def logout(request): """ 清空session的函数 :param request: :return: """ request.session.clear() return redirect("/login.html") def login(request): """ 登录验证 :param request: :return: """ if request.method=="GET": return render(request,"login.html") else: username=request.POST.get("username") pwd = request.POST.get("pwd") obj=models.User.objects.filter(username=username,password=pwd).first() if obj:#如果有这个用户则把用户加到session里,并实例化MenuHelper类 request.session["user_info"]={"nid":obj.id,"username":obj.username} MenuHelper(request,obj.username) return redirect("/index.html") else: return redirect("/login.html") def permission(func):#func=被装饰的函数 def inner(request,*args,**kwargs):#被装饰的函数执行时才执行inner user_info = request.session.get("user_info")#在session中取用户 if not user_info:#没取到则返回登陆页面 return redirect("/login.html") obj = MenuHelper(request, user_info["username"])#在session中取到则实例化MenuHelper类 action_list = obj.actions()#判断当前用户有哪些当前url的权限 if not action_list:#为空则是没权限 return HttpResponse("无权限访问") menu_string = obj.menu_tree()#把html数据取出来 kwargs["menu_string"]=menu_string#当成参数传到被装饰的函数 kwargs["action_list"]=action_list#当成参数传到被装饰的函数 return func(request,*args,**kwargs)#真正执行被装饰的函数的地方 return inner#被装饰的函数被inner代替了 @permission # index=permission(index) def index(request,*args,**kwargs):#kwargs是装饰器传的参数 menu_string=kwargs.get("menu_string") action_list=kwargs.get("action_list") if "GET" in action_list:#判断有没有看的权限 result=models.User.objects.all() else: result=[] return render(request,"index.html",{"menu_string":menu_string,"action_list":action_list})