完整代碼:

1 import re 2 from rbac import models 3 from django.utils.safestring import mark_safe 4 5 def permission_session(user_id,request): 6 """ 7 8 :param user_id: rbac中的user表中一條數據id 9 :param request: 10 :return: 11 """ 12 # obj = models.User.objects.filter(username='楊明').first() 13 # 14 # # x = models.User2Role.objects.filter(user_id=obj.id) 15 # # [User2Role,User2Role,User2Role] 16 # 17 # role_list = models.Role.objects.filter(users__user_id=obj.id) 18 # # [Role,] 19 # from django.db.models import Count 20 # # permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url','action__code').annotate(c=Count('id')) 21 # permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url','action__code').distinct() 22 """ 23 [ 24 {permission_url: '/index.html', action_code:'GET'}, 25 {permission_url: '/index.html', action_code:'POST'}, 26 {permission_url: '/index.html', action_code:'DEL'}, 27 {permission_url: '/index.html', action_code:'Edit'}, 28 {permission_url: '/order.html', action_code:'GET'}, 29 {permission_url: '/order.html', action_code:'POST'}, 30 {permission_url: '/order.html', action_code:'DEL'}, 31 {permission_url: '/order.html', action_code:'Edit'}, 32 ] 33 放在Session中 34 /index.html?md=GET 35 36 { 37 '/index.html': [GET,POST,DEL,Edit], 38 '/order.html': [GET,POST,DEL,Edit], 39 } 40 41 """ 42 43 user_permission_dict = { 44 '/ah-index.html': ["GET","POST","DEL","Edit"], 45 '/order.html': ["GET","POST","DEL","Edit"], 46 '/index-(\d+).html': ["GET","POST","DEL","Edit"], 47 } 48 49 request.session['user_permission_dict'] = user_permission_dict 50 51 52 def menu(user_id,current_url): 53 """ 54 根據用戶ID,當前URL:獲取用戶所有菜單以及權限,是否顯示,是否打開 55 :param user_id: 56 :param current_url: 57 :return: 58 """ 59 # 所有菜單:處理成當前用關聯的菜單 60 all_menu_list = models.Menu.objects.all().values('id','caption','parent_id') 61 user = models.User.objects.filter(id=user_id).first() 62 role_list = models.Role.objects.filter(users__user=user) 63 permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__id','permission__url','permission__menu_id','permission__caption').distinct() 64 ##### 將權限掛靠到菜單上 ######## 65 all_menu_dict = {} 66 for row in all_menu_list: 67 row['child'] = [] # 添加孩子 68 row['status'] = False # 是否顯示菜單 69 row['opened'] = False # 是否默認打開 70 all_menu_dict[row['id']] = row 71 72 for per in permission_list: 73 if not per['permission__menu_id']: 74 continue 75 76 item = { 77 'id':per['permission__id'], 78 'caption':per['permission__caption'], 79 'parent_id':per['permission__menu_id'], 80 'url': per['permission__url'], 81 'status': True, 82 'opened': False 83 } 84 if re.match(per['permission__url'],current_url): 85 item['opened'] = True 86 pid = item['parent_id'] 87 all_menu_dict[pid]['child'].append(item) 88 89 # 將當前權限前輩status=True 90 temp = pid # 1.父親ID 91 while not all_menu_dict[temp]['status']: 92 all_menu_dict[temp]['status'] = True 93 temp = all_menu_dict[temp]['parent_id'] 94 if not temp: 95 break 96 97 # 將當前權限前輩opened=True 98 if item['opened']: 99 temp1 = pid # 1.父親ID 100 while not all_menu_dict[temp1]['opened']: 101 all_menu_dict[temp1]['opened'] = True 102 temp1 = all_menu_dict[temp1]['parent_id'] 103 if not temp1: 104 break 105 # ############ 處理菜單和菜單之間的等級關系 ############ 106 107 result = [] 108 for row in all_menu_list: 109 pid = row['parent_id'] 110 if pid: 111 all_menu_dict[pid]['child'].append(row) 112 else: 113 result.append(row) 114 115 ##################### 結構化處理結果 ##################### 116 117 # for row in result: 118 # print(row['caption'],row['status'],row['opened'],row) 119 120 121 def menu_tree(menu_list): 122 tpl1 = """ 123 <div class='menu-item'> 124 <div class='menu-header'>{0}</div> 125 <div class='menu-body {2}'>{1}</div> 126 </div> 127 """ 128 tpl2 = """ 129 <a href='{0}' class='{1}'>{2}</a> 130 """ 131 132 menu_str = "" 133 for menu in menu_list: 134 if not menu['status']: 135 continue 136 # menu: 菜單,權限(url) 137 if menu.get('url'): 138 # 權限 139 menu_str += tpl2.format(menu['url'],'active' if menu['opened'] else "",menu['caption']) 140 else: 141 # 菜單 142 if menu['child']: 143 child_html = menu_tree(menu['child']) 144 else: 145 child_html = "" 146 menu_str += tpl1.format(menu['caption'], child_html,"" if menu['opened'] else 'hide') 147 148 return menu_str 149 menu_html = menu_tree(result) 150 return menu_html 151 152 153 # simple_tag 154 def css(): 155 v = """ 156 <style> 157 .hide{ 158 display: none; 159 } 160 .menu-body{ 161 margin-left: 20px; 162 } 163 .menu-body a{ 164 display: block; 165 } 166 .menu-body a.active{ 167 color: red; 168 } 169 </style> 170 """ 171 return v 172 173 # simple_tag 174 def js(): 175 v = """ 176 <script> 177 $(function(){ 178 179 $('.menu-header').click(function(){ 180 $(this).next().removeClass('hide').parent().siblings().find('.menu-body').addClass('hide'); 181 182 }) 183 184 }) 185 </script> 186 """ 187 return mark_safe(v)
#另外創建一個app, 動態生成多級菜單,做成一個插件,后另一個APP中如果需要,直接導入:
示例:
APP01下的views.py
from django.shortcuts import render,HttpResponse,redirect from rbac import service,server # Create your views here. def menu_test(request): css=server.css() js=server.js() result=server.menu(1,'/index') # print(result,'[[[[[[') return render(request,'menu.html',{'css':css,'js':js,'result':result})
代碼詳解:
from django.shortcuts import render, HttpResponse, redirect from rbac import models from django.utils.safestring import mark_safe from django.db.models import Q, Count import re def menu(user_id, current_url): # 當前用戶信息 user = models.User.objects.filter(id=user_id).first() # 當前用戶的所有角色 role_list = models.Role.objects.filter(users__user=user) # 這里一跨表就到了Role2User 里面 # p2a = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__url', # 'action__code',) #《 獲取當前用戶角色的權限列表》 permission_list = models.Permission2Action2Role.objects.filter(role__in=role_list).values('permission__id', 'permission__caption', 'permission__url', 'permission__menu', 'permission__menu_id', 'role_id').distinct()
all_menu_list = models.Menu.objects.all().values('id', 'caption', 'parent_id')
1、獲取當前所有菜單
all_menu_list
<QuerySet [{'id': 1, 'caption': '博客管理', 'parent_id': None}, {'id': 2, 'caption': '用戶管理', 'parent_id': None}, {'id': 3, 'caption': '訂單管理', 'parent_id': None}, {'id': 4, 'ca ption': '待處理', 'parent_id': 3}]>
2、菜單的結果中添加child
all_menu_dict = {} for row in all_menu_list: row['child'] = [] #添加孩子 row['status'] = False # 表示是否顯示,最終在頁面上,讓該顯示的顯示 row['opend'] = False # 表示當前默認是否應該展開 all_menu_dict[row['id']] = row # print(all_menu_dict) # print(all_menu_list)
#結果
all_menu_dict={}
for row in all_menu_list:
row[‘child’]=‘’
row[‘status’]=False
row[‘opened’]=False
all_menu_dict[‘id’]=row
結果:
{
1: {'opend': False, 'child': [], 'caption': '博客管理', 'parent_id': None, 'status': False, 'id': 1},
2: {'opend': False, 'child': [], 'caption': '用戶管理', 'parent_id': None, 'status': False, 'id': 2},
3: {'opend': False, 'child': [], 'caption': '訂單管理', 'parent_id': None, 'status': False, 'id': 3},
4: {'opend': False, 'child': [], 'caption': '待處理', 'parent_id': 3, 'status': False, 'id': 4}
}
3、獲取當前用戶角色的權限列表,看上面的《獲取當前用戶角色的權限列表》
<QuerySet
[{'permission__menu': 4, 'permission__menu_id': 4, 'permission__url': '/process', 'permission_id': 4, 'permission__caption': '處理訂單'},
{'permission__menu': 2, 'permission__menu_id': 2, 'permission__url': '/index', 'permission_id': 1, 'permission__caption': '用戶管理'},
{'permission__menu': 3, 'permission__menu_id': 3, 'permission__url': '/order', 'permission_id': 2, 'permission__caption': '訂單管理'}
]>
for per in permission_list: if not per['permission__menu_id']: continue item = { 'id': per['permission__id'],#’permission_id': 2,4 'caption': per['permission__caption'], #'permission__caption': '訂單管理’,,處理訂單,, 'parent_id': per['permission__menu_id'], #'permission__menu_id': 3, 'url': per['permission__url'], #'permission__url': '/order',/process 'status': True, 'opend': False, } if re.match(per['permission__url'],current_url): item['opend'] = True ##item={‘url': '/order', 'status': True, 'opend': True, 'id': 2, 'parent_id': 3, 'caption': '訂單管理'} pid = item['parent_id'] #'parent_id': 3——'permission__menu_id': 4 # all_menu_dict[pid]['child'].append(item) #最后all_menu_dict的結果:
{
1: {'opend': False, 'id': 1, 'status': False, 'caption': '博客管理', 'child': [], 'parent_id': None},
2: {'opend': False, 'id': 2, 'status': False, 'caption': '用戶管理', 'child': [{'url': '/index', 'opend': False, 'id': 1, 'status': True, 'caption': '用戶管理', 'parent_id': 2}], 'parent_id': None},
3: {'opend': False, 'id': 3, 'status': False, 'caption': '訂單管理', 'child': [{'url': '/order', 'opend': True, 'id': 2, 'status': True, 'caption': '訂單管理', 'parent_id': 3}], 'parent_id': None},
4: {'opend': False, 'id': 4, 'status': False, 'caption': '待處理', 'child': [{'url': '/process', 'opend': False, 'id': 4, 'status': True, 'caption': '處理訂單', 'parent_id': 4}], 'parent_id': 3}
}
# 將當前權限前輩的[status]=True temp = pid while not all_menu_dict[temp]['status']: all_menu_dict[temp]['status'] = True temp = all_menu_dict[temp]['parent_id'] if not temp: break # # 將當前權限前輩opend=True if item['opend']: temp1 = pid while not all_menu_dict[temp1]['opend']: all_menu_dict[temp1]['opend'] = True temp1 = all_menu_dict[temp1]['parent_id'] if not temp1: break # print(all_menu_dict) # 當前URL # all_menu_dict[pid]['status']=True # all_menu_dict[all_menu_dict[pid]['parent_id']]['status']=True # print(item)#{'opend': False, 'id': 3, 'parent_id': 1, 'status': True, 'url': '/blogs.html', 'caption': '博客管理'} # print(all_menu_dict)# # {1: {'opend': False, 'caption': '用戶管理', 'status': False, 'parent_id': None, 'id': 1, # 'child': [{'url': '/blogs.html', 'opend': False, 'caption': '博客管理', 'status': True, 'parent_id': 1, 'id': 3}]}, # 2: {'opend': False, 'caption': '訂單管理', 'status': False, 'parent_id': None, 'id': 2, 'child': []}, # 3: {'opend': False, 'caption': '博客管理', 'status': False, 'parent_id': 1, 'id': 3, 'child': [{'url': '/user.html', 'opend': False, 'caption': '用戶管理', 'status': True, 'parent_id': 3, 'id': 1}]}, # 4: {'opend': False, 'caption': '任務管理', 'status': False, 'parent_id': 2, 'id': 4, 'child': []}, 5: {'opend': False, 'caption': '待處理任務', 'status': False, 'parent_id': 4, 'id': 5, 'child': []} # } # ######處理菜單和菜單之間的等級關系# # print(all_menu_list) result = [] # 最終結構化數據結果 for row in all_menu_list: pid = row['parent_id'] if pid: # print(row) all_menu_dict[pid]['child'].append(row) else: result.append(row) ###結構化數據處理結束 最后結果result變成這樣:
result=
[{'child': [], 'id': 1, 'status': False, 'parent_id': None, 'caption': '博客管理', 'opend': False},
{'child': [{'id': 1, 'url': '/index', 'status': True, 'parent_id': 2, 'caption': '用戶管理', 'opend': False}], 'id': 2, 'status': True, 'parent_id': None, 'caption': '用戶管理', 'opend': False},
{'child': [{'id': 2, 'url': '/order', 'status': True, 'parent_id': 3, 'caption': '訂單管理', 'opend': True},{'child': [{'id': 4, 'url': '/process', 'status': True, 'parent_id': 4, 'caption': '處理訂單','opend':False}],
'id': 4, 'status': True, 'parent_id': 3, 'caption': '待處理', 'opend': False}], 'id': 3, 'status': True, 'parent_id': None, 'caption': '訂單管理', 'opend': True}]
#前端生成HTML標簽:
def menu_tree(menu_list): tpl1 = """ <div class='menu-item'> <div class='menu-header'>{0}</div> <div class='menu-body {2}'>{1}</div> </div> """ tpl2 = """ <a href='{0}' class='{1}'>{2}</a> """ menu_str = "" for menu in menu_list: # for menu in menu_list: if not menu['status']: continue # if not menu['status']: # continue if menu.get('url'): # 權限 menu_str += tpl2.format(menu['url'], 'active' if menu['opend'] else "", menu['caption']) else: # 菜單 # 如果是菜單就還有child if menu['child']: child_html = menu_tree(menu['child']) else: child_html = "" menu_str += tpl1.format(menu['caption'], child_html, "" if menu['opend'] else 'hide') return menu_str menu_html = menu_tree(result) return menu_html # ####生成菜單 # return render(request,'menus.html') def css(): v = """ <style> .hide{ display: none; } .menu-body{ margin-left: 20px; } .menu-body a{ display: block; } .menu-body a.active{ color: red; } </style> """ return v # simple_tag def js(): v = """ <script> $(function(){ $('.menu-header').click(function(){ $(this).next().removeClass('hide').parent().siblings().find('.menu-body').addClass('hide'); }) }) </script> """ return mark_safe(v)
最后效果: