先上一张,效果图。 OK
开始做:
用户信息 和 角色。很容易就能搞成。 只需要从数据库取出。 menu 和 role 两张表的全部数据, 再模板进行循环的渲染就行了。
all_user_queryset = models.UserInfo.objects.all() all_role_queryset = models.Role.objects.all()
拿到数据,前端直接渲染就好了!

{% extends "layout.html" %} {% block css %} <style type="text/css"> tr.active { border-left: #eea236 solid 2px; } </style> {% endblock %} {% load rbac_tags %} {% block content %} <div class="luffy-container"> <div class="col-md-3"> <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"><i class="fa fa-book" aria-hidden="true"></i>员工信息</div> <div class="panel panel-body"> <ul> {% for user in all_user_list %} <li><a href="">{{ user.name }}</a></li> {% endfor %} </ul> </div> </div> </div> <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-heading"><i class="fa fa-binoculars" aria-hidden="true"></i>角色信息</div> <div class="panel panel-body"> 提示:点击用户后才能为其分配角色 <table class="table table-condensed"> <thead> <tr> <th>角色</th> <th>选项</th> </tr> </thead> <tbody> {% for role in all_role_list %} <tr> <td><a href="">{{role.title}}</a></td> <td><input type="checkbox" name="roles" value="{{ role.id }}"></td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </div> {% endblock %}
最后的 权限分配这里,才是重点:
可以看到的是, 这有一个层级结构。 业务管理 为一级菜单。 账单列表为二级菜单。 其余的就是 各属于二级菜单之下的 权限。
所以如果 在模板进行渲染的时候, 是一个 列表嵌套字典的格式,会容易许多:
比如这样的:
{
'mid': 1,
'title': '用户管理',
'children': [{
'id': 1,
'title': '客户列表',
'menu_id': 1,
'children': [{
'id': 2,
'title': '添加客户',
'pid_id': 1
}, {
'id': 3,
'title': '修改客户',
'pid_id': 1
}, {
'id': 4,
'title': '删除客户',
'pid_id': 1
}, {
'id': 5,
'title': '批量导入',
'pid_id': 1
}, {
'id': 6,
'title': '下载模板',
'pid_id': 1
}]
}]
}
这样子中三层的,层级结构。 传给模板的时候,就只需要。 三层循环就可以了!
如果你想递归, 我也有 递归的方法。(一个用于渲染评论树的代码)
第一步也是没啥好所的, 先从数据库把 所有的数据取出来:
# 所有的一级菜单 all_menu_queryset = models.Menu.objects.values("mid", "title") # 所有的二级菜单 all_second_menu_queryset = models.Permission.objects.filter(menu_id__isnull=False).values("id", "title", "menu_id") # 所有的不是二级菜单的权限 all_permission_queryset = models.Permission.objects.filter(menu_id__isnull=True).values("id", "title", "pid_id")
这里有一点 必须要说明: Python 的赋值是使用的, 引用机制。 所以才会有下面方法的, 构造数据的方式:
这里可能会有疑惑,为什么更新的是字典。 但是最后用的却是最初循环的列表呢?
all_menu_dict = {} # 只是为了,在循环中查找数据方便,创建的字典 for item in all_menu_queryset: item["children"] = [] all_menu_dict[item.get("mid")] = item # 我这里在循环的时候, 给all_menu_queryset中每一个item(这是一个字典)添加了一个 ["children"] = []。
注意!!!! 我是先添加了一个键值对, 才保存到all_menu_dict字典中的。 所以当我下面的循环,在对这个字典中的 ["children"] = [] 这个列表进行添加操作
的时候。 改变的不仅仅是 我这个字典的数据。 会连带着all_menu_queryset中的数据,也会发生变化! 因为python 的引用机制。 大家使用的都是同一块内存地址
all_second_menu_dict = {} for row in all_second_menu_queryset: row["children"] = [] all_second_menu_dict[row.get("id")] = row menu_id = row.get("menu_id") # 如果没数据库没有做关联的话, 这里要判断以下 是否有这个 menu_id all_menu_dict.get(menu_id).get("children").append(row) # 因为我的数据库是做了关联的,所以才能在这里直接查找赋值。 for row in all_permission_queryset: pid_id = row.get("pid_id") if not pid_id: continue all_second_menu_dict.get(pid_id).get("children").append(row)
queryset 是一种类似于, 列表的结构。 最终所有的数据, 都保存在了 all_menu_queryset 这个里面。
然后就是, 所有判断,当前用户是谁。 让权限表,角色表。 让相应的 checkbox 带上 checked 属性。 这里就需要让后台知道当前用户点击的
还是 老套路。 在用户和角色的的 标签上!加上 ?uid=1 和 ?uid=1&rid=1。 如果忘了,就去前面的博客复习。
https://www.cnblogs.com/chengege/p/10710371.html
然后是,视图部分代码逻辑:

user_id = request.GET.get('uid') role_id = request.GET.get('rid') user_obj = models.UserInfo.objects.filter(pk=user_id).first() role_obj = models.Role.objects.filter(pk=role_id).first() if not user_obj: user_id = None if not role_obj: role_id = None # 获取当前用户所拥有的角色. 进行默认选择 if user_id: user_has_role = user_obj.roles.all().values("id") else: user_has_role = [] user_has_role_dict = {item["id"]: None for item in user_has_role} # 如果选中了角色,优先显示选中的角色,拥有的权限。 如果没有选择角色,才显示用户的所有权限 if role_obj: user_has_permissions = role_obj.permissions.all() user_has_permissions_dict = {item.id: None for item in user_has_permissions} elif user_obj: user_has_permissions = user_obj.roles.values("permissions__id").distinct() # 获取当前用户所拥有的所有权限 user_has_permissions_dict = {item["permissions__id"]: None for item in user_has_permissions} else: user_has_permissions_dict = {}
前端使用同一个,user_has_permissions_dict 。在后台 进行判断。 如果用户选中了角色,优先显示选中的角色,拥有的权限。 如果没有选择角色,才显示用户的所有权限。
最后是,提交保存的代码:

if request.method == "POST" and request.POST.get("type") == "role": role_id_list = request.POST.getlist("roles") if not user_obj: return HttpResponse("请选择用户,不要自己添加input标签。烦得很") user_obj.roles.set(role_id_list) # 通过用户找到 roles 然后set 向他们的关系表。 更新数据 if request.method == "POST" and request.POST.get("type") == "permission": permission_id_list = request.POST.getlist("permissions") if not user_obj or not role_obj: return HttpResponse("请选择用户,不要自己添加input标签。烦得很") role_obj.permissions.set(permission_id_list)
这里用到了, ORM 中。 对多对多关系表,更新的 set() 方法。
头昏脑涨:太晚了!先放上所有代码:

def distribute_permission(request): ''' 权限分配 :param request: :return: ''' user_id = request.GET.get('uid') role_id = request.GET.get('rid') user_obj = models.UserInfo.objects.filter(pk=user_id).first() role_obj = models.Role.objects.filter(pk=role_id).first() if request.method == "POST" and request.POST.get("type") == "role": role_id_list = request.POST.getlist("roles") if not user_obj: return HttpResponse("请选择用户,不要自己添加input标签。烦得很") user_obj.roles.set(role_id_list) # 通过用户找到 roles 然后set 向他们的关系表。 更新数据 if request.method == "POST" and request.POST.get("type") == "permission": permission_id_list = request.POST.getlist("permissions") if not user_obj or not role_obj: return HttpResponse("请选择用户,不要自己添加input标签。烦得很") role_obj.permissions.set(permission_id_list) if not user_obj: user_id = None if not role_obj: role_id = None # 获取当前用户所拥有的角色. 进行默认选择 if user_id: user_has_role = user_obj.roles.all().values("id") else: user_has_role = [] user_has_role_dict = {item["id"]: None for item in user_has_role} # 如果选中了角色,优先显示选中的角色,拥有的权限。 如果没有选择角色,才显示用户的所有权限 if role_obj: user_has_permissions = role_obj.permissions.all() user_has_permissions_dict = {item.id: None for item in user_has_permissions} elif user_obj: user_has_permissions = user_obj.roles.values("permissions__id").distinct() # 获取当前用户所拥有的所有权限 user_has_permissions_dict = {item["permissions__id"]: None for item in user_has_permissions} else: user_has_permissions_dict = {} all_user_queryset = models.UserInfo.objects.all() all_role_queryset = models.Role.objects.all() # 所有的一级菜单 all_menu_list = models.Menu.objects.values("mid", "title") # 所有的二级菜单 all_second_menu_queryset = models.Permission.objects.filter(menu_id__isnull=False).values("id", "title", "menu_id") # 所有的不是二级菜单的权限 all_permission_queryset = models.Permission.objects.filter(menu_id__isnull=True).values("id", "title", "pid_id") all_menu_dict = {} for item in all_menu_list: item["children"] = [] all_menu_dict[item.get("mid")] = item all_second_menu_dict = {} for row in all_second_menu_queryset: row["children"] = [] all_second_menu_dict[row.get("id")] = row menu_id = row.get("menu_id") all_menu_dict.get(menu_id).get("children").append(row) for row in all_permission_queryset: pid_id = row.get("pid_id") if not pid_id: continue all_second_menu_dict.get(pid_id).get("children").append(row) return render(request, "rbac/distribute_permissions.html", {"all_user_list": all_user_queryset, "all_role_list": all_role_queryset, "all_menu_queryset": all_menu_list, "user_id": user_id, "role_id": role_id, "user_has_role_dict": user_has_role_dict, "user_has_permissions_dict": user_has_permissions_dict})

{% extends "layout.html" %} {% block css %} <style> table { font-size: 12px; } .panel-body{font-size: 12px;margin-bottom: 0} .user-area ul { padding-left: 20px; } .user-area li { cursor: pointer; padding: 2px 0; } .user-area li a { display: block; } .user-area li.active { font-weight: bold; color: red; } .user-area li.active a { color: red; } .role-area tr td a { display: block; } .role-area tr.active { background-color: #f1f7fd; border-left: 3px solid #fdc00f; } .panel-body { font-size: 12px; } .permission-area tr.root { background-color: #f1f7fd; } .permission-area tr.root td i { margin: 3px; } .permission-area .node { } .permission-area .node input[type='checkbox'] { margin: 0 5px; } .permission-area .node .parent { padding: 5px 0; } .permission-area .node label { font-weight: normal; margin-bottom: 0; font-size: 12px; } .permission-area .node .children { padding: 0 0 0 20px; } .permission-area .node .children .child { display: inline-block; margin: 2px 5px; } .select-help { float: right; } .select-help label { font-weight: normal; cursor: pointer; } .select-help .check-all { float: left; display: inline-block; margin-right: 8px; } </style> {% endblock %} {% load rbac_tags %} {% block content %} <div class="luffy-container"> <div class="col-md-3 user-area"> <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"><i class="fa fa-book" aria-hidden="true"></i>员工信息</div> <div class="panel panel-body"> <ul> {% for user in all_user_list %} <li class="{% if user_id == user.id|safe %}active{% endif %}"> <a href="?uid={{ user.id }}">{{ user.name }}</a></li> {% endfor %} </ul> </div> </div> </div> <div class="col-md-3 role-area"> <div class="panel panel-default"> <form method="post"> {% csrf_token %} <input type="hidden" name="type" value="role"> <div class="panel-heading"><i class="fa fa-binoculars" aria-hidden="true">角色信息</i> {% if user_id %} <button type="submit" class="right btn btn-success btn-xs" style="padding: 2px 8px;margin: -3px;"> <i class="fa fa-save" aria-hidden="true"> 保存</i> </button> {% endif %} </div> <div class="panel panel-body" style="color: #737373"> 提示:点击用户后才能为其分配角色 </div> <table class="table table-condensed"> <thead> <tr> <th>角色</th> <th>选项</th> </tr> </thead> <tbody> {% for role in all_role_list %} <tr class="{% if role.id|safe == role_id %}active{% endif %}"> <td> {% if user_id %} <a href="?uid={{ user_id }}&rid={{ role.id }}">{{ role.title }}</a> {% else %} <a href="?rid={{ role.id }}">{{ role.title }}</a> {% endif %} </td> <td> <input {% if role.id in user_has_role_dict %}checked{% endif %} type="checkbox" name="roles" value="{{ role.id }}"> </td> </tr> {% endfor %} </tbody> </table> </form> </div> </div> <div class="col-md-6 permission-area"> <div class="panel panel-default"> <form method="post"> {% csrf_token %} <input type="hidden" name="type" value="permission"> <div class="panel-heading"><i class="fa fa-binoculars" aria-hidden="true">权限分配</i> {% if role_id %} <button type="submit" class="right btn btn-success btn-xs" style="padding: 2px 8px;margin: -3px;"> <i class="fa fa-save" aria-hidden="true"> 保存</i> </button> {% endif %} </div> <div class="panel panel-body"> 提示:必须要选择角色,才可以分配权限 </div> <table class="table"> <tbody> {% for item in all_menu_queryset %} <tr class="root"> <td> <i class="fa fa-caret-down" aria-hidden="true"></i> {{ item.title }} <div class="select-help"> <div class="check-all"> <label for="check_all_{{ item.mid }}">全选</label> <input id="check_all_{{ item.mid }}" type="checkbox"> </div> </div> </td> </tr> {% if item.children %} <tr class="node"> <td> {% for node in item.children %} <div class="parent"> <input id="permission_{{ node.id }}" name="permissions" {% if node.id in user_has_permissions_dict %}checked{% endif %} value="{{ node.id }}" type="checkbox"> <label for="permission_{{ node.id }}">{{ node.title }}(菜单)</label> </div> <div class="children"> {% for child in node.children %} <div class="child"> <input id="permission_{{ child.id }}" name="permissions" {% if child.id in user_has_permissions_dict %}checked{% endif %} type="checkbox" value="{{ child.id }}"> <label for="permission_{{ child.id }}">{{ child.title }}</label> </div> {% endfor %} </div> {% endfor %} </td> </tr> {% endif %} {% endfor %} </tbody> </table> </form> </div> </div> </div> {% endblock %} {% block js %} <script type="text/javascript"> $(function () { $(".check-all input:checkbox").change(function () { $(this).parents(".root").next().find("input:checkbox").prop("checked", $(this).prop("checked")); }) }) </script> {% endblock %}