rbac组件权限分配之权限批量操作

示例效果图:

rbac组件权限分配之权限批量操作

 

 

 rbac组件权限分配之权限批量操作

 

 rbac组件权限分配之权限批量操作

 

 app01/urls.py

from django.conf.urls import re_path
from app01.views import customer
from app01.views import payment
from app01.views import account

urlpatterns = [

    re_path(r'^customer/list/$', customer.customer_list, name='customer_list'),  # 把name全部加上
    re_path(r'^customer/add/$', customer.customer_add, name='customer_add'),
    re_path(r'^customer/edit/(?P<cid>\d+)/$', customer.customer_edit, name='customer_edit'),
    re_path(r'^customer/del/(?P<cid>\d+)/$', customer.customer_del, name='customer_del'),
    re_path(r'^customer/import/$', customer.customer_import, name='customer_import'),
    re_path(r'^customer/tpl/$', customer.customer_tpl, name='customer_tpl'),

    re_path(r'^payment/list/$', payment.payment_list, name='payment_list'),
    re_path(r'^payment/add/$', payment.payment_add, name='payment_add'),
    re_path(r'^payment/edit/(?P<pid>\d+)/$', payment.payment_edit, name='payment_edit'),
    re_path(r'^payment/del/(?P<pid>\d+)/$', payment.payment_del, name='payment_del'),

    re_path(r'^login/', account.login, name='login'),

    re_path(r"^", account.login),
]

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'^multi/permissions/$', menu.multi_permissions, name="multi_permissions"),
    re_path(r'^multi/permissions/del/(?P<pk>\d+)/$', menu.multi_permissions_del, name="multi_permissions_del"),
]

rbac/forms/menu.py

from django import forms
from rbac import models


class MultiAddPermissionForm(forms.Form):
    title = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    url = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    name = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    menu_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )
    pid_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super(MultiAddPermissionForm, self).__init__(*args, **kwargs)
        self.fields["menu_id"].choices += models.Menu.objects.values_list("id", "title")
        self.fields["pid_id"].choices += models.Permission.objects.filter(
            pid__isnull=True
        ).exclude(menu__isnull=True).values_list("id", "title")


class MultiEditPermissionForm(forms.Form):
    id = forms.IntegerField(
        widget=forms.HiddenInput(),
        required=False,
    )
    title = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    url = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    name = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    menu_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )
    pid_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super(MultiEditPermissionForm, self).__init__(*args, **kwargs)
        self.fields["menu_id"].choices += models.Menu.objects.values_list("id", "title")
        self.fields["pid_id"].choices += models.Permission.objects.filter(
            pid__isnull=True
        ).exclude(menu__isnull=True).values_list("id", "title")

rbac/views/menu.py

from django.shortcuts import render, redirect, HttpResponse
from rbac import models
from rbac.forms.menu import MenuModelForm, SecondMenuModelForm, PermissionModelForm, MultiAddPermissionForm, \
    MultiEditPermissionForm
from rbac.service.urls import memory_reverse
from rbac.service.routes import get_all_url_dict
from collections import OrderedDict
from django.forms import formset_factory


def multi_permissions(request):
    """
    批量操作权限
    :param request:
    :return:
    """
    post_type = request.GET.get("type")
    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)
    generate_formset = None
    update_formset = None
    if request.method == "POST" and post_type == "generate":
        # 批量添加
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            object_list = []
            post_row_list = formset.cleaned_data
            has_error = False
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                try:
                    new_object = models.Permission(**row_dict)
                    new_object.validate_unique()
                    object_list.append(new_object)
                except Exception as e:
                    formset.errors[i].update(e)
                    generate_formset = formset
                    has_error = True
            if not has_error:
                models.Permission.objects.bulk_create(object_list, batch_size=100)
        else:
            generate_formset = formset
    if request.method == "POST" and post_type == "update":
        # 批量更新
        formset = update_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                permission_id = row_dict.pop("id")
                try:
                    row_object = models.Permission.objects.filter(id=permission_id).first()
                    for k, v in row_dict.items():
                        setattr(row_object, k, v)
                    row_object.validate_unique()
                    row_object.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    update_formset = formset
        else:
            update_formset = formset
    # 1 获取项目中所有的URL
    all_url_dict = get_all_url_dict()
    router_name_set = set(all_url_dict.keys())
    # 2 获取数据库中所有的URL
    permissions = models.Permission.objects.all().values("id", "title", "name", "url", "menu_id", "pid_id")
    permission_dict = OrderedDict()
    for row in permissions:
        permission_dict[row["name"]] = row
    permission_name_set = set(permission_dict.keys())
    for name, value in permission_dict.items():
        router_row_dict = all_url_dict.get(name)
        if not router_row_dict:
            continue
        if value["url"] != router_row_dict["url"]:
            value["url"] = "路由和数据库中不一致..."
    # 3 应该添加、删除、修改的权限有哪些?
    # 3.1 计算出应该增加的name
    if not generate_formset:
        generate_name_list = router_name_set - permission_name_set  # 添加

        generate_formset = generate_formset_class(
            initial=[row_dict for name, row_dict in all_url_dict.items() if name in generate_name_list]
        )
    # 3.2 计算出应该删除的name
    delete_name_list = permission_name_set - router_name_set  # 删除
    delete_row_list = [row_dict for name, row_dict in permission_dict.items() if name in delete_name_list]
    # 3.3 计算出应该更新的name
    if not update_formset:
        update_name_list = router_name_set & permission_name_set  # 修改

        update_formset = update_formset_class(
            initial=[row_dict for name, row_dict in permission_dict.items() if name in update_name_list]
        )

    return render(
        request,
        "rbac/multi_permissions.html",
        {
            "generate_formset": generate_formset,
            "delete_row_list": delete_row_list,
            "update_formset": update_formset,
        }
    )


def multi_permissions_del(request, pk):
    """
    批量操作权限的页面删除
    :param request:
    :param pk:
    :return:
    """
    url = memory_reverse(request, "rbac:multi_permissions")
    if request.method == "GET":
        return render(request, "rbac/delete.html", {"cancel": url})
    models.Permission.objects.filter(id=pk).delete()
    return redirect(url)

rbac/templates/rbac/multi_permissions.html

{% extends 'layout.html' %}

{% block content %}
    <div class="luffy-container">
        {# 添加 #}
        <form method="post" action="?type=generate">
        {% csrf_token %}
        {{ generate_formset.management_form }}
        <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <i class="fa fa-th-list" aria-hidden="true"></i>
                待新建权限列表
                <button href="#" class="right btn btn-primary btn-xs"
                   style="padding: 2px 8px; margin: -3px;">
                    <i class="fa fa-save" aria-hidden="true"></i>
                    新建
                </button>
            </div>

            <!-- Table -->
            <table class="table">
                <thead>
                <tr>
                    <th>序号</th>
                    <th>名称</th>
                    <th>URL</th>
                    <th>别名</th>
                    <th>菜单</th>
                    <th>父权限</th>
                </tr>
                </thead>
                <tbody>
                {% for form in generate_formset %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        {% for field in form %}
                            <td>{{ field }} <span style="color: red">{{ field.errors.0 }}</span></td>
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
        </form>
        {# 删除 #}
        <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <i class="fa fa-th-list" aria-hidden="true"></i>
                待删除权限列表
            </div>

            <!-- Table -->
            <table class="table">
                <thead>
                <tr>
                    <th>序号</th>
                    <th>名称</th>
                    <th>URL</th>
                    <th>别名</th>
                    <th>删除</th>
                </tr>
                </thead>
                <tbody>
                {% for form in delete_row_list %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        <td>{{ form.title }}</td>
                        <td>{{ form.url }}</td>
                        <td>{{ form.name }}</td>
                        <td><a href="{% url 'rbac:multi_permissions_del' pk=form.id %}" style="color: #d9534f">
                            <i class="fa fa-trash-o"></i>
                        </a></td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
        {# 更新 #}
        <form method="post" action="?type=update">
        {% csrf_token %}
        {{ update_formset.management_form }}
        <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <i class="fa fa-th-list" aria-hidden="true"></i>
                待更新权限列表
                <button href="#" class="right btn btn-primary btn-xs"
                   style="padding: 2px 8px; margin: -3px;">
                    <i class="fa fa-save" aria-hidden="true"></i>
                    更新
                </button>
            </div>

            <!-- Table -->
            <table class="table">
                <thead>
                <tr>
                    <th>序号</th>
                    <th>名称</th>
                    <th>URL</th>
                    <th>别名</th>
                    <th>菜单</th>
                    <th>父权限</th>
                </tr>
                </thead>
                <tbody>
                {% for form in update_formset %}
                    <tr>
                        <td>{{ forloop.counter }}</td>
                        {% for field in form %}
                            {% if forloop.first %}
                                {{ field }}
                            {% else %}
                            <td>{{ field }} <span style="color: red">{{ field.errors.0 }}</span></td>
                            {% endif %}
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
        </form>
    </div>
{% endblock %}

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">
                <!-- Default panel contents -->
                <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 -->
                <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">
                <!-- Default panel contents -->
                <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 -->
                <table class="table">
                    <thead>
                    <tr>
                        <th>名称</th>
                        {# 让code和url两个信息显示在同一列,这样就不会因为信息过长而影响整个页面展示 #}
                        <th>CODE&URL</th>
                        <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-5">
            <div class="panel panel-default">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <i class="fa fa-cogs" aria-hidden="true"></i>
                    权限
                    {# 如果选中了二级菜单,那么就显示新建按钮 #}
                    <div class="btn-group right">
                        {% 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 %}
                        <a href="{% memory_url request 'rbac:multi_permissions' %}" class="btn btn-primary btn-xs"
                           style="padding: 2px 8px; margin: -3px 0;">
                            <i class="fa fa-mail-forward" aria-hidden="true"></i>
                            批量操作
                        </a>
                    </div>
                </div>
                <!-- Table -->
                <table class="table">
                    <thead>
                    <tr>
                        <th>名称</th>
                        {# 让code和url两个信息显示在同一列,这样就不会因为信息过长而影响整个页面展示 #}
                        <th>CODE&URL</th>
                        <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>
    </div>
{% endblock %}

链接:https://pan.baidu.com/s/1VvxYPgmNJD-8MJUGnnEpxQ 

提取码:abab

rbac组件权限分配之权限批量操作

 

上一篇:springmvc执行流程


下一篇:Spring,SpringMVC,SpringBoot,SpringCloud有什么区别和联系?