如何制作一个简单的django权限组件
Posted 春秋羽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何制作一个简单的django权限组件相关的知识,希望对你有一定的参考价值。
第一步:
新建一个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代码根据自己设计的页面来写
组件的使用方法
先设置settings文件
INSTALLED_APPS下添加 \'rbac.apps.RbacConfig\'
MIDDLEWARE下添加\'rbac.middleware.rbac.RbacPermissionMiddleware\'
PERMISSION_SESSION_KEY = \'permission_dict\' # 设置存储当前用户可以访问的地址的key
MENU_SESSION_KEY=\'menu_dict\' # 存储菜单相关的列表的key
WITER_LIST = [\'^/login/$\', # 白名单
\'^/reg/$\',
\'^/admin/.*$\']
在自己的view中使用要导入
from rbac.service.init_permission import init_permission
当登录成功
import init_permission(request,当前用户的对象)
以上是关于如何制作一个简单的django权限组件的主要内容,如果未能解决你的问题,请参考以下文章