zoukankan      html  css  js  c++  java
  • 权限组件(13):批量操作权限页面的展示和增删改查

    效果图:

    一、路由配置

    rbac/urls.py
    配置一个批量操作页面的路由和删除权限的路由

    ...
    from django.urls import re_path
    
    from rbac.views import menu
    ...
    
    urlpatterns = [
        ...
        # 批量操作权限
        re_path(r'^multi/permissions/$', menu.multi_permissions, name='multi_permissions'),  # 自动发现项目中的所有URL
        re_path(r'^multi/permissions/delete/(?P<pk>d+)', menu.multi_permissions_delete, name='multi_permissions_delete')
        ...
    ]

     

    二、forms表单验证

    rbac/forms/menu.py

    ...
    from django import forms
    ...
    
    ...
    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().__init__(*args, **kwargs)
            self.fields['menu_id'].choices += models.Menu.objects.all().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()
        )  # 获取用户id,进行修改操作
        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().__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.forms.models 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) # 储存的所有信息,包括html标签 if formset.is_valid(): has_repeat_error = False permission_obj_list = [] url_form_list = formset.cleaned_data for num in range(0, formset.total_form_count()): url_form = url_form_list[num] # 下面的方式和model.Permission.object.create(**row)效果一样,这里用这种方式是为了捕获唯一性错误 try: permission_obj = models.Permission(**url_form) permission_obj.validate_unique() # 检查当前对象在数据库是否存在唯一的 permission_obj_list.append(permission_obj) except Exception as e: formset.errors[num].update(e) # 把错误信息放到对应的form里面 generate_formset = formset # 要把用户批量增加时出错的错误信息传给模板 has_repeat_error = True if not has_repeat_error: models.Permission.objects.bulk_create(permission_obj_list, batch_size=formset.total_form_count()) else: generate_formset = formset # 出错信息传给模板 # 批量更新 if request.method == 'POST' and post_type == 'update': formset = update_formset_class(data=request.POST) if formset.is_valid(): url_form_list = formset.cleaned_data for num in range(0, formset.total_form_count()): url_form = url_form_list[num] permission_id = url_form.pop('id') try: permission_obj = models.Permission.objects.filter(id=permission_id).first() for key, value in url_form.items(): setattr(permission_obj, key, value) permission_obj.validate_unique() permission_obj.save() except Exception as e: formset.errors[num].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()) # 所有路由中的url集合 """ set里不能有重复的值,转换成set后只会剩下key { 'rbac:menu_list': {'name': 'rbac:menu_list', 'url': 'xxxxx/yyyy/menu/list'} } 会变成 {'rbac:menu_list'} """ # # 2. 获取数据库中所有的url all_db_permissions = models.Permission.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id') db_permission_name_set = set() # 数据库中的set集合 db_permission_dict = OrderedDict() for db_permission in all_db_permissions: db_permission_dict[db_permission[ 'name']] = db_permission # {'rbac:menu_list':{'id':1,'title':'角色列表',name:'rbac:role_list',url:'/rbac/role/list'},} db_permission_name_set.add(db_permission['name']) # {'rbac:menu_list','rbac:menu_add'......} for name, value in db_permission_dict.items(): router_row_dict = all_url_dict.get(name) # {'name':'rbac:role_list','url':'/rbac/role/list'}, if not router_row_dict: # 没有别名和url的直接跳过 continue if value['url'] != router_row_dict['url']: # 数据库里的url和自动发现的url进行对比 value['url'] = '路由和数据库中的不一致' # 3. 应该添加、删除和修改的权限 # 3.1 计算出应该添加的name if not generate_formset: """ 如果目标没有通过验证,generate_formset的值就是上面出错了的formset,就不会执行下面的代码,页面就会显示错误信息 如果通过验证,就会返回给页面自动发现的数据库中有、路由中没有的url。 下面的 if not update_formset同理 """ generate_name_list = router_name_set - db_permission_name_set generate_formset = generate_formset_class( initial=[add_url for name, add_url in all_url_dict.items() if name in generate_name_list] ) # 3.2 计算出应该删除的name : 数据库有,路由中没有 delete_url_name_list = db_permission_name_set - router_name_set # 数据库里的url - 路由中的url delete_url_list = [delete_url_obj for name, delete_url_obj in db_permission_dict.items() if name in delete_url_name_list] # 3.3 计算出应该更新的name :数据库和路由中都有 if not update_formset: update_name_list = db_permission_name_set & router_name_set # 都包含的元素 update_formset = update_formset_class( initial=[update_url for name, update_url in db_permission_dict.items() if name in update_name_list] ) context = { 'generate_formset': generate_formset, 'delete_url_list': delete_url_list, 'update_formset': update_formset, } return render(request, 'rbac/multi_permissions.html', context) def multi_permissions_delete(request, pk): """ 批量页面的权限删除 :param request: :param pk: :return: """ multi_pemrission_url = memory_reverse(request, 'rbac:multi_permissions') if request.method == 'GET': return render(request, 'rbac/delete.html', {'cancel': multi_pemrission_url}) models.Permission.objects.filter(id=pk).delete() return redirect(multi_pemrission_url)

    四、模板

    rbac/templates/multi_permissions.html

    {% extends 'layout.html' %}
    
    {% block content %}
        <div class="luffy-container">
    
            <!-- 待新建的权限列表 -->
            <form action="?type=generate" method="post">
                {% csrf_token %}
                {{ generate_formset.management_form }}
    
                <div class="panel panel-success">
                    <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 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-danger">
                <!-- Default panel contents -->
                <div class="panel-heading">
                    <i class="fa fa-th-list" aria-hidden="true">数据库中有,路由中没有的权限列表</i>
                </div>
    
                <table class="table">
                    <thead>
                    <tr>
                        <th>序号</th>
                        <th>名称</th>
                        <th>URL</th>
                        <th>别名</th>
                        <th>删除</th>
                    </tr>
                    </thead>
    
                    <tbody>
                    {% for delete_url_obj in delete_url_list %}
                        <tr>
                            <td>{{ forloop.counter }}</td>
                            <td>{{ delete_url_obj.title }}</td>
                            <td>{{ delete_url_obj.url }}</td>
                            <td>{{ delete_url_obj.name }}</td>
                            <td>
                                <a style="color: red; font-size:18px"
                                   href="{% url 'rbac:multi_permissions_delete' delete_url_obj.id %}">
                                    <i class="fa fa-trash-o" aria-hidden="true"></i>
                                </a>
                            </td>
    
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>
    
            <!-- 待更新的权限列表 -->
            <form action="?type=update" method="post">
                {% csrf_token %}
                {{ update_formset.management_form }}
                <div class="panel panel-primary">
                    <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-plus-circle" aria-hidden="true">更新</i>
                        </button>
                    </div>
    
                    <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 content %}

    在rbac/templates/menu_list.html的权限表里加上批量操作权限的按钮

    {% extends 'layout.html' %}
    {% load rbac %}
    
    {% block css %}
        <style>
            tr.active {
                border-left: 3px solid #fdc00f;
            }
        </style>
    {% endblock css %}
    
    {% 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 %}
                            <!-- 管道符可以将后端传来的整型,转换成字符串 -->
                            <tr class="{% if menu.id|safe == menu_id %}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; font-size:18px"
                                       href="{% memory_url request 'rbac:menu_edit' pk=menu.id %}">
                                        <i class="fa fa-edit" aria-hidden="true"></i>
                                    </a>
    
                                    <a style="color: red; font-size:18px"
                                       href="{% memory_url request 'rbac:menu_delete' pk=menu.id %}">
                                        <i class="fa fa-trash-o" aria-hidden="true"></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-flag" aria-hidden="true">二级菜单</i>
    
                        {% if menu_id %}
                            <a href="{% memory_url request 'rbac:second_menu_add' menu_id=menu_id %}"
                               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>
                            <th>CODE&URL</th>
                            <th>选项</th>
                        </tr>
                        </thead>
                        <tbody>
                        {% for second_menu in second_menus %}
                            <!-- 管道符可以将后端传来的整型,转换成字符串 -->
                            <tr class="{% if second_menu.id|safe == second_menu_id %}active{% endif %}">
                                <td rowspan="2"><a
                                        href="?mid={{ menu_id }}&sid={{ second_menu.id }}">{{ second_menu.title }}</a>
                                </td>
                                <td>{{ second_menu.name }}</td>
                                <td>
                                    <a style="color: #333333; font-size:18px"
                                       href="{% memory_url request 'rbac:second_menu_edit' pk=second_menu.id %}">
                                        <i class="fa fa-edit" aria-hidden="true"></i>
                                    </a>
    
                                    <a style="color: red; font-size:18px"
                                       href="{% memory_url request 'rbac:second_menu_delete' pk=second_menu.id %}">
                                        <i class="fa fa-trash-o" aria-hidden="true"></i>
                                    </a>
                                </td>
                            </tr>
    
                            <tr class="{% if second_menu.id|safe == second_menu_id %}active{% endif %}">
                                <td colspan="2" style="border-top:0;">{{ second_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-flag" aria-hidden="true">权限</i>
    
    
                        <div class="btn-group right">
                            {% if second_menu_id %}
    
                                <a href="{% memory_url request 'rbac:permission_add' second_menu_id=second_menu_id %}"
                                   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 right btn-primary 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>CODE&URL</th>
                                <th>选项</th>
                            </tr>
                            </thead>
                            <tbody>
                            {% for permission in permissions %}
                                <!-- 管道符可以将后端传来的整型,转换成字符串 -->
                                <tr class="">
                                    <td rowspan="2">{{ permission.title }}</td>
                                    <td>{{ permission.name }}</td>
                                    <td>
                                        <a style="color: #333333; font-size:18px"
                                           href="{% memory_url request 'rbac:permission_edit' pk=permission.id %}">
                                            <i class="fa fa-edit" aria-hidden="true"></i>
                                        </a>
    
                                        <a style="color: red; font-size:18px"
                                           href="{% memory_url request 'rbac:permission_delete' pk=permission.id %}">
                                            <i class="fa fa-trash-o" aria-hidden="true"></i>
                                        </a>
                                    </td>
                                </tr>
    
                                <tr class="">
                                    <td colspan="2" style="border-top:0;">{{ permission.url }}</td>
                                </tr>
                            {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
    
            </div>
        </div>
    
    
    {% endblock content %}
  • 相关阅读:
    舍不得花钱的心理分析
    DLL编程的导入导出,__declspec(dllimport),__declspec(dllexport)
    浅谈C/C++内存泄漏及其检测工具
    C++多线程编程简单实例
    linux镜像源设置
    Linux基础教程 linux无密码ssh登录设置
    兄弟连教育分享:用CSS实现鼠标悬停提示的方法
    PHP基础教程 PHP的页面缓冲处理机制
    Linux基础教程 linux下cat 命令使用详解
    PHP基础教程 php 网络上关于设计模式一些总结
  • 原文地址:https://www.cnblogs.com/lshedward/p/10528580.html
Copyright © 2011-2022 走看看