效果图:

增加页面:

编辑页面:

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

数据库

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. Oracle的表操作,约束

    回顾MySQL创建表语句users(id整型/name字符串/birthday日期型,默认今天)drop table if exists users;create table if not exist ...

  2. 并发包阻塞队列之ArrayBlockingQueue

    并发包阻塞队列之ArrayBlockingQueue   jdk1.7.0_79  上一节中对并发包中的非阻塞队列ConcurrentLinkedQueue的入队.出队做了一个简要的分析,本文将对并发 ...

  3. Java并发(六):并发策略

    通过多次优化实例来了解选择并发策略的正确姿势 通过模拟浏览器程序的渲染页面(Page-Rendering)功能,为了方便,假设HTML页面只会包含标签文本和图片以及URL; 第一个版本:串行加载页面元 ...

  4. 解决移动端浏览器页面 X轴横向滚动条问题

    写web端页面的时候,总是会出现横向滚动条,即 X 轴滚动条,导致页面左右滑来滑去. 即使设置了 body,html {overflow-x:hidden;width:100%;} 也无法生效. 解决 ...

  5. Unicode字符集

    Unicode字符集的出现是为了弥补ASCII码只能表示128个字符的限制.在实际应用中,如若我们想显示汉字或日文等等,显然使用ASCII是不可能的.Unicode占用了两个字节,即16位,能表示的字 ...

  6. Linux 下查找指令

    原文链接:http://www.cnblogs.com/sunleecn/archive/2011/11/01/2232210.html whereis <程序名称>查找软件的安装路径-b ...

  7. linux下如何实现mysql数据库定时自动备份

    概述   备份是容灾的基础,是指为防止系统出现操作失误或系统故障导致数据丢失,而将全部或部分数据集合从应用主机的硬盘或阵列复制到其它的存储介质的过程.而对于一些网站.系统来说,数据库就是一切,所以做好 ...

  8. IOS Prefix.pch程序常见文件 的作用

    #import <Availability.h> #ifndef __IPHONE_5_0 #warning "This project uses features only a ...

  9. 2017.12.11 String 类中常用的方法

    1.编写程序将 "jdk" 全部变为大写,并输出到屏幕,截取子串"DK" 并输出到屏幕 package demo; import java.util.Scann ...

  10. Symfony相关网站参考

    http://www.doctrine-project.org/projects.html 数据库相关知识 http://firehare.blog.51cto.com/809276/703599整合 ...