第一步:
新建一个app
第二步:目录结构
第三步:代码如下
第一步:写models
from django.db import models # 定义一级菜单 class Menu(models.Model): title = models.CharField(max_length=32, unique=True) # 名称 icon = models.CharField(max_length=32, null=True, blank=True) # 图标代码:可以为空 def __str__(self): return self.title # 定义权限 class Permission(models.Model): """ 权限表 """ title = models.CharField(verbose_name=‘标题‘, max_length=32) # 定义标题,动态生成时候,要用到 url = models.CharField(verbose_name=‘含正则的URL‘, max_length=128) # url地址 name = models.CharField(max_length=32, verbose_name=‘url别名‘, unique=True) # 每个url的别名,唯一,且不能为空 menu = models.ForeignKey(‘Menu‘, null=True, blank=True, verbose_name=‘一级菜单‘) # 关联的一级菜单 prent = models.ForeignKey(‘Permission‘, null=True, blank=True, verbose_name=‘关联列表‘) # 自己关联自己中的某个列表要使用的 def __str__(self): return self.title class Role(models.Model): """ 角色 """ title = models.CharField(verbose_name=‘角色名称‘, max_length=32) # 定义角色的名字 permissions = models.ManyToManyField(verbose_name=‘拥有的所有权限‘, to=‘Permission‘, blank=True) # 和权限多对多关系 def __str__(self): return self.title # 定义用户 class UserInfo(models.Model): """ 用户表 """ name = models.CharField(verbose_name=‘用户名‘, max_length=32) # 账号 password = models.CharField(verbose_name=‘密码‘, max_length=64) # 密码 email = models.CharField(verbose_name=‘邮箱‘, max_length=32) # 邮箱 roles = models.ManyToManyField(verbose_name=‘拥有的所有角色‘, to=‘Role‘, blank=True) # 多对多关联角色表 def __str__(self): return self.name
第二步:写server文件下的init_permission.py
from django.conf import settings # 获取当前登录用户的所有权限 def init_permission(request, user): rbac_list = user.roles.filter(permissions__url__isnull=False).values( ‘permissions__id‘, # 获取权限的id ‘permissions__url‘,# 获取权限的url ‘permissions__title‘,# 获取权限的名字 ‘permissions__name‘,# 获取权限的别名 ‘permissions__prent_id‘,# 获取关联列表的id ‘permissions__prent__name‘,# 获取关联列表的别名 ‘permissions__menu_id‘,# 获取一级菜单的id ‘permissions__menu__title‘,# 获取一级菜单的名字 ‘permissions__menu__icon‘, # 获取一级菜单的图标代码 ).distinct() # 去重 url_dict = {} # 该用户所有的权限 menu_dic = {} # 根据权限生成的菜单 for i in rbac_list: # 循环所有筛选出来的内容 """ 用每个权限的别名做key, value是[ ‘url‘:权限的url, ‘id‘:每个权限的id, ‘pid‘:‘它所关联权限的id‘, ‘title‘:‘它自己的标题‘, ‘pname‘:‘它所关联权限的别名‘ ] """ url_dict[i[‘permissions__name‘]] = {‘url‘: i[‘permissions__url‘], ‘id‘:i[‘permissions__id‘], ‘pid‘:i[‘permissions__prent_id‘], ‘title‘:i[‘permissions__title‘], ‘pname‘:i[‘permissions__prent__name‘], } # 获取一级菜单的id menu_id = i.get(‘permissions__menu_id‘) # 判断如果没有一级菜单的id就重新循环 if not menu_id: continue # 判断一级菜单的id是否存在menu_dic这个字典里 # 如果存在 if menu_id not in menu_dic: """ 结构: 一级菜单id = { ‘title‘:一级菜单的名称 ‘icon‘:一级菜单的图标代码 ‘children‘:[{ ‘title‘:二级菜单的标题, ‘url‘:二级菜单的url ‘id‘:二级菜单的id }]} """ menu_dic[i[‘permissions__menu_id‘]] = { ‘title‘: i[‘permissions__menu__title‘], ‘icon‘: i[‘permissions__menu__icon‘], ‘children‘: [ {‘title‘: i[‘permissions__title‘], ‘url‘: i[‘permissions__url‘], ‘id‘:i[‘permissions__id‘] } ] } else: menu_dic[i[‘permissions__menu_id‘]][‘children‘].append({‘title‘: i[‘permissions__title‘], ‘url‘: i[‘permissions__url‘], ‘id‘: i[‘permissions_id‘] }) # 把筛选出来的该用户所有权限和菜单结构全部存入到session中 # settings.PERMISSION_SESSION_KEY和settings.MENU_SESSION_KEY:自己在自己的settings文件中设置 request.session[settings.PERMISSION_SESSION_KEY] = url_dict request.session[settings.MENU_SESSION_KEY] = menu_dic
第三步:写middlewear下的rbac.py
import re from django.conf import settings from django.shortcuts import HttpResponse from django.utils.deprecation import MiddlewareMixin # 中间件 class RbacPermissionMiddleware(MiddlewareMixin): def process_request(self, request): # 获取当前访问的地址 current_url = request.path_info # 循环判断白名单,自己在settings设置自己的白名单 for i in settings.WITER_LIST: if re.match(‘^%s$‘%i, current_url): return # 获取当前用户权限 permissions_dict = request.session[settings.PERMISSION_SESSION_KEY] # 小菜单要使用 request.breadcrumb_list=[{‘title‘:‘首页‘,‘url‘:‘/‘}] # 循环判断 flag = False # 循环用户的所有权限 for item in permissions_dict.values(): # 正则匹配 if re.match(item[‘url‘], current_url): # 匹配成功修改flag flag = True # 获取id,父级id,父级url别名 id = item[‘id‘] pid = item[‘pid‘] pname = item[‘pname‘] # 判断是否有父级id if pid: # 获取父级id,在动态生成菜单时要用 request.current_menu_id = pid # 父级的url,title,和自己的url好和title request.breadcrumb_list.extend([ {‘url‘:permissions_dict[pname][‘url‘],‘title‘:permissions_dict[pname][‘title‘]}, {‘url‘:item[‘url‘],‘title‘:item[‘title‘]}, ]) else: # 获取自己id,在动态生成菜单时要用 request.current_menu_id = id # 自己的url好和title request.breadcrumb_list.extend([ {‘url‘: item[‘url‘], ‘title‘: item[‘title‘]} ]) break # 判断当前用户是否有权限访问这个页面 if not flag: return HttpResponse(‘你没有此权限‘)
第四步:写templatetags下的rbac.py
from django.conf import settings from django import template from collections import OrderedDict register = template.Library() # 设置左侧菜单的模板组件 @register.inclusion_tag(‘rbac/module.html‘) def show_results(request): # 获取存储菜单的字典 menu_dic = request.session[settings.MENU_SESSION_KEY] # 让字典变的有序,python3.6在一些特殊的情况下会变得无序 order_dict = OrderedDict() # 循环这个字典,字典先排序 for item in sorted(menu_dic): # 把这个字典里所有内容传入到有序字典里 order_dict[item] = menu_dic[item] # 给所有的一级菜单中都加入一个hide(隐藏) order_dict[item][‘class‘] = ‘hide‘ # 循环这个字典的二级菜单 for i in order_dict[item][‘children‘]: # 判断当前访问的url的id是否是当前循环二级菜单的id if request.current_menu_id == i[‘id‘]: # 如果是的话,给他添加‘active‘和去除一级菜单的‘hide‘ i[‘class‘] = ‘active‘ order_dict[item][‘class‘] = ‘‘ # 把字典出入html文件里 return {‘menu_dic‘: order_dict} # 设置小菜单 @register.inclusion_tag(‘rbac/breadcrumb.html‘) def breadcrumb(request): # 把小菜单需要的列表传入 return {‘breadcrumb_list‘: request.breadcrumb_list} # 设置过滤器 @register.filter def has_permission(request, name): # 判断传入的url别名是否在菜单字典中 if name in request.session.get(settings.PERMISSION_SESSION_KEY): return True
<div class="multi-menu"> {% for item in menu_dic.values %} <div class="item"> <div class="title"> <span class="icon-wrap"><i class="fa {{ item.icon }}"></i></span>{{ item.title }} </div> <div class="body {{ item.class }}"> {% for per in item.children %} <a href="{{ per.url }}" class="{{ per.class }}" >{{ per.title }}</a> {% endfor %} </div> </div> {% endfor %} </div>
<ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;"> {% for item in breadcrumb_list %} {% if forloop.last %} <li class="active">{{ item.title }}</li> {% else %} <li><a href="{{ item.url }}">{{ item.title }}</a></li> {% endif %} {% endfor %} </ol>
第五步:admin.py中的代码
from django.contrib import admin from rbac import models class PermissionAdmin(admin.ModelAdmin): list_display = [‘title‘, ‘url‘,‘menu‘,‘prent‘,‘name‘] # 页面要显示的内容 list_editable = [‘url‘,‘menu‘,‘prent‘,‘name‘] # 可以在页面更改的内容 admin.site.register(models.Role) admin.site.register(models.Permission, PermissionAdmin) admin.site.register(models.UserInfo) admin.site.register(models.Menu)
有一些注释可能写的比较迷,直接贴图吧
左菜单/大菜单
小菜单
简单的组件写完了,组件的css和js代码根据自己设计的页面来写
组件的使用
第一步:
原文:https://www.cnblogs.com/chunqiuyu/p/9769280.html