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 %}