效果图:

增加页面:

编辑页面:

因为后面要对权限进行批量操作,所以先用这个示例演示下如何实现批量操作

数据库

from django.db import models

class Menu(models.Model):
"""
菜单表
"""
title = models.CharField(verbose_name='菜单名称', max_length=32)
icon = models.CharField(verbose_name='图标', max_length=32) def __str__(self):
return self.title class Permission(models.Model):
"""
权限表
"""
title = models.CharField(verbose_name='标题', max_length=32)
url = models.CharField(verbose_name='含正则的URL', max_length=128) name = models.CharField(verbose_name='URL的别名', max_length=32, unique=True) menu = models.ForeignKey(verbose_name='所属菜单', to='Menu', null=True, blank=True,
help_text='null表示不是菜单;非null表示是二级菜单', on_delete=models.CASCADE) pid = models.ForeignKey(verbose_name='关联的权限', to='Permission', null=True, blank=True, related_name='parents',
help_text='对于非菜单权限需要选择一个可以成为菜单的权限,用于做默认展开和选中菜单',
on_delete=models.CASCADE) def __str__(self):
return self.title

一、配置路由

from django.urls import path
from formset import views urlpatterns = [
path('multi/add', views.multi_add),
path('multi/edit', views.multi_edit),
]

二、forms表单验证

from django import forms

from formset import models

class MultiPermissionForm(forms.Form):
title = forms.CharField()
url = forms.CharField()
name = forms.CharField()
menu_id = forms.ChoiceField(
choices=[(None, '----------')],
required=False
)
pid_id = forms.ChoiceField(
choices=[(None, '----------')],
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') class MultiUpdatePermissionForm(forms.Form):
id = forms.IntegerField(
widget=forms.HiddenInput()
)
title = forms.CharField()
url = forms.CharField()
name = forms.CharField()
menu_id = forms.ChoiceField(
choices=[(None, '----------')],
required=False
)
pid_id = forms.ChoiceField(
choices=[(None, '----------')],
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')

三、视图函数

from django.forms import formset_factory
from django.shortcuts import render, HttpResponse from formset import models
from formset.forms.formset import MultiPermissionForm, MultiUpdatePermissionForm def multi_add(request):
"""
批量增加
:param request:
:return:
""" formset_class = formset_factory(MultiPermissionForm, extra=5) # 在内部生成五个form表单 if request.method == 'GET':
formset = formset_class()
return render(request, 'multi_add.html', {'formset': formset}) formset = formset_class(data=request.POST) # 储存的所有信息,包括html标签
if formset.is_valid():
no_repeat_field = True # 要把cleaned_data放到for循环上面,因为在下面一旦cleaned_data检测到错误信息就会报错。里面储存了一个个form[{},{},{}......]
form_list = formset.cleaned_data # 检查formset中有没有错误信息,没有则将用户提交的数据取到。有错误信息就报错
for num in range(0, formset.total_form_count()):
form = form_list[num] # 一个具体的form
if not form:
continue
try:
# 下面的方式和model.Permission.object.create(**row)效果一样,这里用这种方式是为了捕获唯一性错误
permission_obj = models.Permission(**form)
permission_obj.validate_unique() # 检查当前对象在数据库是否存在唯一的
permission_obj.save()
except Exception as e:
formset.errors[num].update(e) # 把错误信息放到对应的form里面
no_repeat_field = False if no_repeat_field:
return HttpResponse('提交成功')
else:
return render(request, 'multi_add.html', {'formset': formset})
return render(request, 'multi_add.html', {'formset': formset}) def multi_edit(request):
formset_class = formset_factory(MultiUpdatePermissionForm, extra=0) # 默认等于1,如果不想让它多增加一个,就把默认改成0
if request.method == 'GET':
formset = formset_class(
initial=models.Permission.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id')
)
return render(request, 'multi_edit.html', {'formset': formset}) formset = formset_class(data=request.POST)
if formset.is_valid():
no_repeat_field = True
form_list = formset.cleaned_data
for num in range(0, formset.total_form_count()):
form = form_list[num]
if not form:
continue
permission_id = form.pop('id')
try:
permission_obj = models.Permission.objects.filter(id=permission_id).first()
for key, value in form.items():
setattr(permission_obj, key, value) # 更新数据库的字段
permission_obj.validate_unique()
permission_obj.save()
except Exception as e:
formset.errors[num].update(e)
no_repeat_field = False
if no_repeat_field:
return HttpResponse("提交成功")
else:
return render(request, 'multi_edit.html', {'formset': formset})
return render(request, 'multi_edit.html', {'formset': formset})

四、模板渲染

multi_add.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
</head>
<body> <div class="container" style="margin-top: 100px">
<div class="row">
<form action="" method="post" novalidate>
{% csrf_token %}
{{ formset.management_form }}
<table class="table table-hover table-stripped" border="1">
<thead>
<tr>
<th>标题</th>
<th>URL</th>
<th>Name</th>
<th>菜单</th>
<th>父权限</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
{% for field in form %}
<td>
{{ field }}
<span style="color:red">{{ field.errors.0 }}</span>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<hr/>
<input type="submit" value="提交" class="btn btn-primary">
</form>
</div>
</div> </body>
</html>

multi_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
</head>
<body> <div class="container" style="margin-top: 100px">
<div class="row">
<form action="" method="post" novalidate>
{% csrf_token %}
{{ formset.management_form }}
<table class="table table-hover table-stripped" border="1">
<thead>
<tr>
<th>标题</th>
<th>URL</th>
<th>Name</th>
<th>菜单</th>
<th>父权限</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
{% 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>
<hr/>
<input type="submit" value="提交" class="btn btn-primary">
</form>
</div>
</div> </body>
</html>

edit和add的区别是edit多了个id并把id隐藏起来了

权限组件(11):基于formset实现批量增加的更多相关文章

  1. rbac 权限分配, 基于formset实现,批量增加

    这里需要两个知识点: - formset - 自动发现项目中的URL1. 什么是formset: Django中 form组件 或 ModelForm组件,用于做一个表单的验证. 接收前端form表单 ...

  2. rbac 权限分配, 基于formset实现,批量编辑

    已经完成了  批量添加的功能. 还想要一个批量修改的功能了.随之而来的第一个问题就是,  我们的formset 并不是一条记录.而是 多条记录,甚至整个表的记录.那么显而易见的问题就是,当前端页面把数 ...

  3. CRM第一篇:权限组件之权限控制

    一.权限组件(1):一级菜单 二.权限组件(2):二级菜单 三.权限组件(3):默认选中非菜单(二级菜单) 四.权限组件(4):给动态菜单增加面包屑导航 五.权限组件(5):权限粒度控制到按钮 六.权 ...

  4. Web端权限管理新增实用功能:批量增加操作,简单方便快速!

    扩展了吉日嘎拉的Web端权限管理功能后,每次添加菜单倒没啥问题,毕竟菜单的数量有限,可是每增加一个模块.功能或者说权限控制点,就得针对各种常规操作,新增很多遍. 浪费时间,还容易出错.新增了一个字典表 ...

  5. CRM【第一篇】: 权限组件之权限控制

    1. 问:为什么程序需要权限控制? 答:生活中的权限限制,① 看灾难片电影<2012>中富人和权贵有权登上诺亚方舟,穷苦老百姓只有等着灾难的来临:② 屌丝们,有没有想过为什么那些长得漂亮身 ...

  6. Django-CRM项目学习(七)-权限组件的设置以及权限组件的应用

    开始今日份整理 1.利用自定制标签,增加展示权限,权限分级设定 1.1 在权限组件中创建自定义标签 使用自定义标签的目的,使各个数据进行分离 1.2 导入自定义标签包 自定义标签复习(自定义标签有三种 ...

  7. python 全栈开发,Day107(CRM初始,权限组件之权限控制,权限系统表设计)

    一.CRM初始 CRM,客户关系管理系统(Customer Relationship Management).企业用CRM技术来管理与客户之间的关系,以求提升企业成功的管理方式,其目的是协助企业管理销 ...

  8. rbac权限组件整合到实际项目的全过程详述

    rbac简介 项目的GitHub地址 欢迎Download&Fork&Star:https://github.com/Wanghongw/CombineRbac 另外,本文只简单介绍一 ...

  9. day 71 crm(8) 权限组件的设置,以及权限组件的应用

    ---恢复内容开始--- 前情提要: strak 组件是增删改查组件 , 生活中,需求权限组件,  不足: 1,前后端不分离,   2, 空url也会刷新界面,造成资源浪费   3,如果角色忘记设置权 ...

随机推荐

  1. Sql server 数据库的备份和还原数据库提示“ 加载的介质已格式化为支持 1 个介质簇,但根据指定的备份设备,应支持 2 个介质簇”

     数据库备份和还原总结 在 "M:\2017-Pro\company\other\databak_2014-10\anquanbaowei_db_201704300200.BAK" ...

  2. webpack.config.js====引入Jquery库文件

    1. 安装 cnpm install --save jquery expose-loader 2. 在webpack.config.js中配置 Jquery库是使用的webpack的一个插件Provi ...

  3. 虚拟机安装CentOS7 Minimal、jdk和hadoop

    虚拟机安装CentOS7 Minimal.jdk和hadoop Table of Contents 1. 安装版本 2. PD安装 3. vim安装和配置 4. 主机名变为bogon的解决办法 5. ...

  4. 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强

    本文转自:http://www.trinea.cn/android/preloaddatacache/ 本文主要介绍一个支持自动向前或向后获取新数据的缓存的使用及功能.Android图片内存缓存可见I ...

  5. Python 加持,给你更有趣的 Azure 虚拟机开关重启方法!

    在程序员的世界里,有关编程语言孰优孰劣的争论从来就没有消停过,不管你更粉哪种语言,毫无疑问,每种语言都有自己擅长的领域,而一些语言因为上手简单.扩展性强.功能强大等因素,往往会比较多地出现在我们面前, ...

  6. linux 命令——55 traceroute(转)

    通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一 ...

  7. Python开发第二篇

    运算符 1.算术运算符 % 取余运算符,返回余数 ** 幂运算符 //返回商的整数部分 2.逻辑运算符 and  与运算符 a and b 如果a为False是,表达式为False,如果a为True返 ...

  8. C语言标准库之setjmp

    协程的介绍 协程(coroutine),意思就是“协作的例程”(co-operative routines),最早由Melvin Conway在1963年提出并实现.跟主流程序语言中的线程不一样,线程 ...

  9. UVALive 4731 Cellular Network(贪心,dp)

    分析: 状态是一些有序的集合,这些集合互不相交,并集为所有区域.显然枚举集合元素是哪些是无法承受的, 写出期望的计算式,会发现,当每个集合的大小确定了以后,概率大的优先访问是最优的. 因此先对u从大到 ...

  10. 【洛谷4424】[HNOI/AHOI2018] 寻宝游戏(位运算思维题)

    点此看题面 大致题意: 给你\(n\)个\(m\)位二进制数.每组询问给你一个\(m\)位二进制数,要求你从\(0\)开始,依次对于这\(n\)个数进行\(and\)或\(or\)操作,问有多少种方案 ...