rbac组件权限分配之权限展示
示例效果:
功能讲解:
权限的新建按钮,只有点击二级菜单后才会显示;添加新的权限,默认为所点击的二级菜单进行添加新的权限,可以看到在前端的添加页面没有pid这个字段,在后端代码中已经设置了pid的值;
rbac/urls.py
from django.urls import re_path from rbac.views import role from rbac.views import user from rbac.views import menu urlpatterns = [ # 角色管理 re_path(r'^role/list/$', role.role_list, name="role_list"), re_path(r'^role/add/$', role.role_add, name="role_add"), re_path(r'^role/edit/(?P\d+)/$ ', role.role_edit, name="role_edit"), re_path(r'^role/del/(?P\d+)/$ ', role.role_del, name="role_del"), # 用户管理 re_path(r'^user/list/$', user.user_list, name="user_list"), re_path(r'^user/add/$', user.user_add, name="user_add"), re_path(r'^user/edit/(?P\d+)/$ ', user.user_edit, name="user_edit"), re_path(r'^user/del/(?P\d+)/$ ', user.user_del, name="user_del"), re_path(r'^user/reset/password/(?P\d+)/$ ', user.user_reset_pwd, name="user_reset_pwd"), # 一级菜单管理 re_path(r'^menu/list/$', menu.menu_list, name="menu_list"), re_path(r'^menu/add/$', menu.menu_add, name="menu_add"), re_path(r'^menu/edit/(?P\d+)/$ ', menu.menu_edit, name="menu_edit"), re_path(r'^menu/del/(?P\d+)/$ ', menu.menu_del, name="menu_del"), # 二级菜单管理 re_path(r'^second/menu/add/(?P\d+)/$ ', menu.second_menu_add, name="second_menu_add"), re_path(r'^second/menu/edit/(?P\d+)/$ ', menu.second_menu_edit, name="second_menu_edit"), re_path(r'^second/menu/del/(?P\d+)/$ ', menu.second_menu_del, name="second_menu_del"), # 权限展示 re_path(r'^permissions/add/(?P\d+)/$ ', menu.permission_add, name="permission_add"), re_path(r'^permissions/edit/(?P\d+)/$ ', menu.permission_edit, name="permission_edit"), re_path(r'^permissions/del/(?P\d+)/$ ', menu.permission_del, name="permission_del"), ]
rbac/views/menu.py
from django.shortcuts import render, redirect, HttpResponse from rbac import models from rbac.forms.menu import MenuModelForm, SecondMenuModelForm, PermissionModelForm from rbac.service.urls import memory_reverse def menu_list(request): """ 菜单和权限列表 :param request: :return: """ menus = models.Menu.objects.all().order_by("pk") # menu_list.html的菜单名称是a标签,此a标签的href在当前url后面加了mid参数 # 取到该参数后,传给模板,模板与所循环一级菜单的id进行if比较,如果相等,那么加上'active'表示选中 menu_id = request.GET.get("mid") # 用户选择的一级菜单 second_menu_id = request.GET.get("sid") # 用户选择的二级菜单 # 如果一级菜单的id不存在,那么将menu_id设置为None,menu_id控制二级菜单的'新建'按钮 if not models.Menu.objects.filter(id=menu_id).exists(): menu_id = None # 如果二级菜单id不存在,那么就将其设置为None,控制权限新建按钮的显示 if not models.Permission.objects.filter(id=second_menu_id).exists(): second_menu_id = None # 如果一级菜单id存在,那么将二级菜单的数据信息查询出来传给模板;如果一级菜单id为空,查询到的数据 # 是不能作为二级菜单的url,所以还需要做一个判断,即一级菜单为空时,二级菜单数据信息为一个空列表 # 那么二级菜单展示也是为空 if menu_id: second_menus = models.Permission.objects.filter(menu_id=menu_id) # 根据一级菜单的id查询二级菜单 else: second_menus = [] # 查询出不能做二级菜单的URL if second_menu_id: permissions = models.Permission.objects.filter(pid_id=second_menu_id) else: permissions = [] return render( request, "rbac/menu_list.html", { "menus": menus, "mid": menu_id, "second_menus": second_menus, "sid": second_menu_id, "permissions": permissions, } ) def permission_add(request, second_menu_id): """ 添加权限 :param request: :param second_menu_id: :return: """ if request.method == "GET": form = PermissionModelForm() return render(request, "rbac/change.html", {"form": form}) form = PermissionModelForm(data=request.POST) if form.is_valid(): second_menu_object = models.Permission.objects.filter(id=second_menu_id).first() if not second_menu_object: return HttpResponse("二级菜单不存在,请重新选择...") form.instance.pid = second_menu_object # 给pid字段设置一个值 form.save() return redirect(memory_reverse(request, "rbac:menu_list")) return render(request, "rbac/change.html", {"form": form}) def permission_edit(request, pk): """ 编辑权限 :param request: :param pk: :return: """ obj = models.Permission.objects.filter(id=pk).first() if not obj: return HttpResponse("权限不存在...") if request.method == "GET": form = PermissionModelForm(instance=obj) return render(request, "rbac/change.html", {"form": form}) form = PermissionModelForm(instance=obj, data=request.POST) if form.is_valid(): form.save() return redirect(memory_reverse(request, "rbac:menu_list")) return render(request, "rbac/change.html", {"form": form}) def permission_del(request, pk): """ 删除权限 :param request: :param pk: :return: """ url = memory_reverse(request, "rbac:menu_list") if request.method == "GET": return render(request, "rbac/delete.html", {"cancel_url": url}) models.Permission.objects.filter(id=pk).delete() return redirect(url)
rbac/forms/menu.py
from django import forms from rbac import models from django.utils.safestring import mark_safe from rbac.forms.base import BootStrapModelForm class PermissionModelForm(BootStrapModelForm): class Meta: model = models.Permission fields = ["title", "name", "url"]
rbac/templates/rbac/menu_list.html
{% extends 'layout.html' %} {% load rbac %} {% block css %} <style> {# 选中样式css #} tr.active { border-left: 3px solid #fdc00f; } style> {% endblock %} {% block content %} <div class="luffy-container"> {# 一级菜单 #} <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-book" aria-hidden="true">i> 一级菜单 <a href="{% memory_url request 'rbac:menu_add' %}" class="right btn btn-success btn-xs" style="padding: 2px 8px; margin: -3px;"> <i class="fa fa-plus-circle" aria-hidden="true">i> 新建 a> div> <table class="table"> <thead> <tr> <th>名称th> <th>图标th> <th>选项th> tr> thead> <tbody> {% for menu in menus %} {# safe也可以转换类型,将数值类型转为了字符串类型 #} <tr class="{% if menu.id|safe == mid %}active{% endif %}"> <td> <a href="?mid={{ menu.id }}">{{ menu.title }}a> td> <td> <i class="fa {{ menu.icon }}" aria-hidden="true">i> td> <td> <a style="color: #333333;" href="{% memory_url request 'rbac:menu_edit' pk=menu.id %}"> <i class="fa fa-edit" aria-hidden="true">i>a> <a style="color: #d9534f;" href="{% memory_url request 'rbac:menu_del' pk=menu.id %}"><i class="fa fa-trash-o">i>a> td> tr> {% endfor %} tbody> table> div> div> {# 二级菜单 #} <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-cog" aria-hidden="true">i> 二级菜单 {# 如果选中了一级菜单,那么就显示新建按钮 #} {% if mid %} <a href="{% memory_url request 'rbac:second_menu_add' menu_id=mid %}" class="right btn btn-success btn-xs" style="padding: 2px 8px; margin: -3px;"> <i class="fa fa-plus-circle" aria-hidden="true">i> 新建 a> {% endif %} div> <table class="table"> <thead> <tr> <th>名称th> {# 让code和url两个信息显示在同一列,这样就不会因为信息过长而影响整个页面展示 #} <th>CODE&URLth> <th>选项th> tr> thead> <tbody> {% for menu in second_menus %} {# 如果选中,那么加active让其显示默认选中效果 #} <tr class="{% if menu.id|safe == sid %}active{% endif %}"> {# 合并两列单元格 #} <td rowspan="2"> {# sid代表二级菜单的id,url如此设计能让后端获取到二级菜单id然后传给模板,模板根据判断进行默认选中效果的展示 #} <a href="?mid={{ mid }}&sid={{ menu.id }}">{{ menu.title }}a> td> <td>{{ menu.name }}td> <td> <a style="color: #333333;" href="{% memory_url request 'rbac:second_menu_edit' pk=menu.id %}"> <i class="fa fa-edit" aria-hidden="true">i>a> <a style="color: #d9534f;" href="{% memory_url request 'rbac:second_menu_del' pk=menu.id %}"><i class="fa fa-trash-o">i>a> td> tr> {# 因为是两行,所以这里也需要加一个active #} <tr class="{% if menu.id|safe == sid %}active{% endif %}"> {# 合并两行单元格,并将上边距设置为0,这样就不会有一条横线了 #} <td colspan="2" style="border-top: 0;">{{ menu.url }}td> tr> {% endfor %} tbody> table> div> div> {# 权限展示 #} <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-cogs" aria-hidden="true">i> 权限 {# 如果选中了二级菜单,那么就显示新建按钮 #} {% if sid %} <a href="{% memory_url request 'rbac:permission_add' second_menu_id=sid %}" class="right btn btn-success btn-xs" style="padding: 2px 8px; margin: -3px;"> <i class="fa fa-plus-circle" aria-hidden="true">i> 新建 a> {% endif %} div> <table class="table"> <thead> <tr> <th>名称th> {# 让code和url两个信息显示在同一列,这样就不会因为信息过长而影响整个页面展示 #} <th>CODE&URLth> <th>选项th> tr> thead> <tbody> {% for menu in permissions %} <tr> {# 合并两列单元格 #} <td rowspan="2"> {{ menu.title }} td> <td>{{ menu.name }}td> <td> <a style="color: #333333;" href="{% memory_url request 'rbac:permission_edit' pk=menu.id %}"> <i class="fa fa-edit" aria-hidden="true">i>a> <a style="color: #d9534f;" href="{% memory_url request 'rbac:permission_del' pk=menu.id %}"><i class="fa fa-trash-o">i>a> td> tr><tr> {# 合并两行单元格,并将上边距设置为0,这样就不会有一条横线了 #} <td colspan="2" style="border-top: 0;">{{ menu.url }}td> tr> {% endfor %} tbody> table> div> div> div> {% endblock %}