一、权限分配
需求:为用户分配角色,为角色分配权限,如下图效果:
1、视图代码:
from django.shortcuts import render
from django.http import JsonResponse
from rbac.models import User, Role, Permission
def distribute_permissions(request):
"""
分配权限
"""
uid = request.GET.get('uid')
user = User.objects.filter(id=uid)
rid = request.GET.get('rid')
# 保存为用户分配的角色,这里需要注意,set方法是先清空后绑定
if request.method == 'POST' and request.POST.get('postType') == 'role':
r_lst = request.POST.getlist("roles")
user.first().roles.set(r_lst)
# 保存为角色分配的权限
if request.method == 'POST' and request.POST.get('postType') == 'permission':
p_lst = request.POST.getlist("permissions_id")
Role.objects.filter(pk=rid).first().permissions.set(p_lst)
user_list = User.objects.all()
role_list = Role.objects.all()
if uid: # 选中某一用户,则显示其对应角色
role_id_list= User.objects.get(pk=uid).roles.all().values_list("pk")
role_id_list = [item[0] for item in role_id_list]
if rid: # 点击某一角色,则显示其对应的权限
per_id_list = Role.objects.filter(pk=rid).values_list("permissions__pk").distinct()
else: # 不点击角色,则显示选中用户对应角色拥有的权限
per_id_list = User.objects.get(pk=uid).roles.values_list("permissions__pk").distinct()
per_id_list = [item[0] for item in per_id_list]
return render(request, 'distribute_permission.html', locals())
# 显示权限表,ajax请求对应的视图函数
def permissions_tree(request):
permissions = Permission.objects.values("pk", "title", "url", "menu__title", "menu__pk", "pid_id")
return JsonResponse(list(permissions), safe=False)
注意:JsonResponse传入一个非字典类型的数据结构时,需要设置safe=False。
2、模板代码
1)显示用户表相关代码
<div class="am-panel-bd">
<ul class="user_ul">
{% for user in user_list %}
<li class={% if user.id|safe == uid %}"active"{% endif %}>
<a href="?uid={{ user.id }}">{{ user.name }}</a>
</li>
{% endfor %}
</ul>
</div>
2)显示角色表相关代码
<table class="am-table table-main mytable">
<thead>
<tr class="am-primary">
<th>角色</th>
<th>选择</th>
</tr>
</thead>
<tbody>
{% for role in role_list %}
<tr class={% if role.id|safe == rid %}"am-danger"{% endif %}>
{% load my_tags %}
<td>
<a href="?{% get_role_url request role.id %}">{{ role.title }}</a>
</td>
<td>
{% if role.id in role_id_list %}
<input type="checkbox" name="roles" value="{{ role.id }}" checked />
{% else %}
<input type="checkbox" name="roles" value="{{ role.id }}" />
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
3)显示权限表相关代码
<div class="am-panel-hd">
<span style="margin-left: 6px;">权限分配</span>
{% if rid %}
<button type="submit" class="am-btn am-fr"></i>保存</button>
{% endif %}
</div>
<p class="per_tips">提示:点击角色后才能为其分配权限</p>
<div class="am-panel-bd mypanel">
<table class="am-table table-main mytable">
<tbody id="tbd">
<!-- 通过文档加载时发送ajax请求获取用户权限,ajax代码如下 -->
</tbody>
</table>
</div>
{% block js %}
<script>
$.ajax({
url:"/rbac/permissions_tree/",
type:"get",
success:function (res) {
console.log(res);
$.each(res, function (i, permission) { // 渲染权限树形结构
console.log(i, permission);
var menu_title = permission["menu__title"];
var menu_pk = permission["menu__pk"];
var url = permission["url"];
var parent_id = permission["pid_id"];
var pk = permission["pk"];
var title = permission["title"];
if (menu_title){ // 如果是菜单权限,即menu_id有值,pid_id为空
// 所属的一级菜单已经存在,则直接追加权限
if($("#menu_"+menu_pk).length){
var s = `
<tr id="per_${pk}">
<td class="">
<div class="">
<label>
<input name="permissions_id" value="${pk}" type="checkbox">
<span>${title}</span>
</label>
</div>
</td>
</tr>
`;
$("#menu_"+menu_pk).parent().append(s);
}else { // 所属的一级菜单不存在,即渲染菜单,又渲染权限
var s = `
<tr class="" id="menu_${menu_pk}">
<td>${menu_title}</td>
</tr>
<tr id="per_${pk}">
<td class="">
<div class="">
<label>
<input name="permissions_id" value="${pk}" type="checkbox">
<span>${title}</span>
</label>
</div>
</td>
</tr>
`;
$("#tbd").append(s);
}
}else { // 如果不是菜单权限,即menu_id为空,pid_id有值
var s = `
<div class="">
<label>
<input name="permissions_id" value="${pk}" type="checkbox">
<span>${title}</span>
</label>
</div>
`;
$("#per_"+parent_id+" td").append(s);
}
});
// 选中角色对应的权限
var per_id_list = {{ per_id_list }}
$.each(per_id_list, function (i, j) {
console.log($("[value='"+j+"']")[0]);
$("#tbd [value='"+j+"']").prop("checked", true);
})
}
})
</script>
{% endblock %}
3、思路分析
此需求难点是将权限表渲染在页面,有两种方案:在前端处理和在后端构建数据结构。
后端构建数据结构比较复杂,涉及到联动等。所以我们可以从前端入手,充分利用jquery的选择器,根据从数据库拿到的权限信息,用jquery技术渲染出来自己需要的结构。
二、将权限组件移植到CRM项目
(1) 先将rbac组件移植到新的项目中;
(2) 将settings中 INSTALLED_APPS 中加入"rbac";
(3) 将新项目的用户表与rbac下的User表一对一关联;
需要注意的是这里是跨app关联,所以需要先引入另一个APP的User表
user=models.OneToOneField(user,null=True,on_delete=models.CASCADE)
(4) 数据迁移;
(5) 在登录成功后引入rbac下的initial_session方法,做登录用户的权限信息存储(注意user对象);
(6) 在setting是中引入rbac下的权限校验中间件;
(7) 在项目的base模板中引入菜单样式,渲染显示;