效果图:

增加页面:

编辑页面:

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

数据库

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. dell电脑 win8换win7重启报错及解决方案

    Win8换win7 bios 识别不到usb选项 按以下操作即可: 把Secure Boot control 改为Disabled 的,F10保存重启,F12进入bios选择usb启动即可: 安装完系 ...

  2. Java 多线程的实现方法

    package com.jckb; /**多线程实现的两种方法 * * @author gx * */ public class Test2 { public static void main(Str ...

  3. orcale函数

    字符函数    1.ASCII 返回与指定的字符对应的十进制数;  select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space ...

  4. 构建高性能JavaScript应用

    前端性能优化准则: 一.减少http请求.     措施:合并小图片,css控制背景图.合并CSS,合并JS 二.使用CDN(Content Deliver Network 内容分发网络)发布静态资源 ...

  5. Unity3d 游戏中集成Firebase 统计和Admob广告最新中文教程

    之前写过俩相关的教程,最近发现插件官方更新了不少内容,所以也更新一篇Firebase Admob Unity3d插件的教程,希望能帮到大家. Firebase Admob Unity3d插件是一个Un ...

  6. iOS核心动画高级技巧之核心动画(三)

    iOS核心动画高级技巧之CALayer(一) iOS核心动画高级技巧之图层变换和专用图层(二)iOS核心动画高级技巧之核心动画(三)iOS核心动画高级技巧之性能(四)iOS核心动画高级技巧之动画总结( ...

  7. Kyligence Analytics Platform Enterprise

    平台: arm 类型: ARM 模板 软件包: kap 2.3 kyanalyzer 2.3 apache kylin basic software bi big data cube data war ...

  8. 当您在 64 位 Windows 上运行 Regsvr32.exe 时出现错误信息

    尝试运行 Regsvr32.exe 注册在 64 位版本的 Windows 32 位动态链接库 (DLL) 时您会收到以下错误消息: 若要解决此问题,从 %SystemRoot%\Syswow64 文 ...

  9. Graylog+elasticsearch+mongodb集群+nginx负载均衡前端

    网上有张图画的很好,搜索有关它的配置文章,google里有几篇英文的,都是依靠haproxy等或别的什么实现,没有纯粹的Graylog+elasticsearch+mongodb集群,项目需要,只有自 ...

  10. IE Proxy Swich - IE 代理切换工具

    通过此工具可方便的切换计算机系统代理设置的开关,无需重启IE 来激活设置 下载 环境要求: 可能需要.NET 4.0 以上平台, 其他平台未测试 截图与功能如下 支持快捷方式参数 我个人习惯是在桌面 ...