
先上一張,效果圖。 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 %}
