django-formset实现数据表的批量操作
什么是formset
我们知道forms组件是用来做表单验证,更准确一点说,forms组件是用来做数据库表中一行记录的验证。有forms组件不同,formset是同科同时验证表中的多行记录,即formset是做表单批量验证的组件。
批量添加
首先要实例化formset对象,对象初始化时需要提供操作表的forms表单类,参数extra
用来显示验证几行数据。将实例化的formset对象传递给前端页面,前端模板通过两层循环:第一层循环form,第二层循环form中的字段。当GET请求时,直接将实例化的formset对象传递给前端。当POST请求时,批量验证表单,当所有数据都没有问题时,后台数据库保存数据。
后台保存数据时,有两种方式:第一种方式简洁,但是无法捕获字段唯一约束的错误;因此使用formset批量添加数据时最好使用第二中方式,手动捕获唯一约束错误信息并交给formset送到前端页面显示。
models.Permission.objects.create(**row)
obj = models.Permission(**row) | obj.save()
唯一约束错误信息捕获的过程,需要使用obj.validate_unique()
判断该对象是否满足唯一约束,如果不满足则通过异常捕获操作,捕获异常信息。通过formset.errors[i].update(e)
把错误信息放入formset中送到前端页面显示。之所以这样做,是因为通过forms组件的验证时无法捕获唯一约束的错误。因此这里通过手动收集错误信息并放入forset中。
此外,如果前端页面渲染的表单没有填写数据,直接提交是不会报错的。formset默认只要不改动字段就不会对该行数据做验证。只要填写一个字段,该行数据则会做表单验证。
# views.py
def multi_add(request):
"""
批量添加
:param request:
:return:
"""
formset_class = formset_factory(MultiPermissionForm, extra=2)
if request.method == 'GET':
formset = formset_class()
return render(request, 'multi_add.html', {'formset': formset})
formset = formset_class(data=request.POST)
if formset.is_valid():
flag = True
# 检查formset中没有错误信息,则讲用户提交的数据获取到。
post_row_list = formset.cleaned_data
for i in range(0, formset.total_form_count()):
row = post_row_list[i]
if not row:
continue
try:
obj = models.Permission(**row)
obj.validate_unique() # 检查当前对象在数据库是否存在唯一的异常。
obj.save()
except Exception as e:
formset.errors[i].update(e)
flag = False
if flag:
return HttpResponse('提交成功')
else:
return render(request, 'multi_add.html', {'formset': formset})
return render(request, 'multi_add.html', {'formset': formset})
前端模板通过两层循环:第一层循环formset得到每一个form,第二层循环form得到每一个字段。与forms组件使用一样,需要手动添加form表单和input提交数按钮及csrf_token跨域伪造请求。此外,使用formset,还需要增加{{ formset.management_form }}
, 使用哪个formset就增加哪个formset.management_form.
# multi_add.html
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
<table 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>
<input type="submit" value="提交">
</form>
批量编辑
批量编辑和批量增加大体是一致的,但是存在不同的使用区别。实例化formset对象时默认extra=1,需要手动修改为extra=0;GET请求,页面需要显示默认值,通过参数initial赋值列表内部嵌套字典的数据结构的数据。且需要传递每行数据的id,告诉formset需要修改的数据id。此时使用的forms类相比批量添加使用的类多一个id字段,id = forms.IntegerField( widget=forms.HiddenInput())
,默认隐藏的字段,前端页面不显示。
同理也会遇到唯一约束错误,使用循环和反射为每个字段做数据更新赋值,然后再提交数据库保存。
def multi_edit(request):
formset_class = formset_factory(MultiUpdatePermissionForm, extra=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():
# 检查formset中没有错误信息,则讲用户提交的数据获取到。
post_row_list = formset.cleaned_data
flag = True
for i in range(0, formset.total_form_count()):
row = post_row_list[i]
if not row:
continue
permission_id = row.pop('id')
try:
permission_object = models.Permission.objects.filter(id=permission_id).first()
for key, value in row.items():
setattr(permission_object, key, value)
permission_object.validate_unique()
permission_object.save()
except Exception as e:
formset.errors[i].update(e)
flag = False
if flag:
return HttpResponse('提交成功')
else:
return render(request, 'multi_edit.html', {'formset': formset})
return render(request, 'multi_edit.html', {'formset': formset})
前端模板循环显示每个字段时,要判断是否是第一个id字段,如果是第一个就直接{{field}}
,页面将不会显示。
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
<table 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>
<input type="submit" value="提交">
</form>
django-formset实现数据表的批量操作的更多相关文章
- django+uwsgi+nginx数据表过大引起"out of memory for query result"
昨天负责的一个项目突然爆“out of memory for query result”. 背景 项目的数据表是保存超过10m的文本数据,通过json方式保存进postgres中,上传一个13m的大文 ...
- Django创建mysql数据表流程
在Django项目建好后,在setting.py中设置好mysql连接参数: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysq ...
- Django Model 数据表
Django Model 定义语法 版本:1.7主要来源:https://docs.djangoproject.com/en/1.7/topics/db/models/ 简单用法 from djang ...
- python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
python Django教程 之 模型(数据库).自定义Field.数据表更改.QuerySet API 一.Django 模型(数据库) Django 模型是与数据库相关的,与数据库相关的代码 ...
- Django之路:模型(数据库)和自定义Field以及数据表的更改
一.Django 模型(数据库) Django模型是与数据库相关的,与数据库相关的代码一般写在models.py中,Django支持sqlite3,MySQL,PostgreSQL等数据库,只需要在s ...
- Django学习手册 - admin后台 切换成中文显示/添加数据表
Django admin后台管理 切换成中文界面: 站点显示为中文: 在setting 里面修改 LANGUAGE_CORE = 'zh-Hans' 字段名显示中文 class Test(models ...
- Django 数据表更改
Django 数据表更改 « Django 开发内容管理系统(第四天) Django 后台 » 我们设计数据库的时候,早期设计完后,后期会发现不完善,要对数据表进行更改,这时候就要用到本节的知识. D ...
- 第三百七十七节,Django+Xadmin打造上线标准的在线教育平台—apps目录建立,以及数据表生成
第三百七十七节,Django+Xadmin打造上线标准的在线教育平台—apps目录建立,以及数据表生成 apps目录建立 我们创建一个apps目录,将所有的app放到apps目录里去,这样方便管理,也 ...
- Django数据库数据表操作
建立表单 django通过设置类来快速建表,打开models.py 例: from __future__ import unicode_literals from django.db import m ...
随机推荐
- mysql设计规范一
原文地址:http://www.jianshu.com/p/33b7b6e0a396 主键 表中每一行都应该有可以唯一标识自己的一列(或一组列). 一个顾客可以使用顾客编号列,而订单可以使用订单ID, ...
- MYSQL结构修改
mysql改表结构主要是5大操作 ADD 添加字段 MODIFY 修改字段类型 CHANGE 修改字段名(也可以修改字段名) DROP 删除字段 RENAME 修改表名 ADD添加新字段:(新字段默认 ...
- NOIP模拟26
把题解沽了好久了,今天还是不想写,我们靠的B卷其实挺水的,但是我就是想吐槽一下!咋还带题目里面放题解的?题里一点题解的线索都没有,但是玄机竟然在题目里! 我也是醉了,T1就是一个贪心,题目说贪婪,T2 ...
- 【原创】使用批处理脚本生成包并自动上传到nuget
Hello 大家好,我是TANZAME,我们又见面了. NuGet 是什么这里就不再重复啰嗦,园子里一搜一大把.今天要跟大家分享的是,在日常开发过程中如何统一管理我们的包,如何通过批处理脚本生成包并自 ...
- T-SQL Part VI: Prevent error message "Saving changes is not permitted" in SSMS
使用SSMS时,经常遇到的问题是,修改一张table时,弹出一个错误对话框:“Saving changes is not permitted”. 这个错误通常是因为以下错误(参阅MSDN的KB文档 h ...
- [剑指offer]删除链表中重复的结点(把重复的都删掉,1个不留)
①题目 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后为 ...
- 前端与算法 leetcode 7. 整数反转
目录 # 前端与算法 leetcode 7. 整数反转 题目描述 概要 提示 解析 解法 算法 传入测试用例的运行结果 执行结果 GitHub仓库 # 前端与算法 leetcode 7. 整数反转 题 ...
- 通过C/C++,实现一元一次方程求解
通过C/C++,实现一元一次方程求解: #include <bits/stdc++.h> using namespace std; string str, str_l, str_r; st ...
- nyoj 283-对称排序 (sort)
283-对称排序 内存限制:64MB 时间限制:1000ms 特判: No 通过数:2 提交数:4 难度:1 题目描述: In your job at Albatross Circus Managem ...
- [springboot 开发单体web shop] 7. 多种形式提供商品列表
上文回顾 上节 我们实现了仿jd的轮播广告以及商品分类的功能,并且讲解了不同的注入方式,本节我们将继续实现我们的电商主业务,商品信息的展示. 需求分析 首先,在我们开始本节编码之前,我们先来分析一下都 ...