django formset实现数据表的批量操作的示例代码
作者:liuxu2019 发布时间:2023-10-10 15:20:21
什么是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>
来源:https://www.cnblogs.com/liuxu2019/p/11992573.html


猜你喜欢
- 这篇文章主要介绍了Python如何基于smtplib发不同格式的邮件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 无法装载DLL Microsoft原因: 126(找不到指定的模块)。 U890帐套引入提示:“无法装载 DLL Microsoft提示您请
- 看过数据库的备份与还原。大多数都是用组件来完成的。其实可通过sql语句来完成。 由于时间关系,未对参数进行验证和界面美化。代码
- 概述虽然Python的强项在人工智能,数据处理方面,但是对于日常简单的应用,Python也提供了非常友好的支持(如:Tkinter),本文主
- 1. desc 命令 格式: desc tablename columnname 例子: desc `table` `mid` desc `
- 问题定义一个int型的一维数组,包含10个元素,分别赋值为1~10, 然后将数组中的元素都向前移一个位置,即,a[0]=a[1],a[1]=
- 以前在一个图书类网站看到这样一个功能:客户可以按条件搜索书目的信息,服务器会将符合条件的信息筛选出来保存为一个Excel文件供客户下载。今天
- 写 python 文件时,每个文件开头都必须注明版本和编码。每次我 touch 文件之后粘贴这两句话让我不胜其烦。由于我没有安装 pytho
- 当使用AJAX进行GET请求的时候,会有一个现象就是刷新网页后,AJAX请求的数据没有改变,只有把IE的缓存清空,或者从新打开一个IE窗口的
- 下面就是简单的例子,这里提供2中方法:test.htm &
- 在这篇文章中,将向您展示如何使用Python链接目前主流的MongoDB(V3.4.0)数据库,主要使用PyMongo(v3.4.0)和Mo
- 目录前言1. 准备工作2. 连接MongoDB3. 指定数据库4. 指定集合5. 插入数据6. 查询7. 计数8. 排序9. 偏移10. 更
- 在应用系统中,尤其在联机事务处理系统中,对数据查询及处理速度已成为衡量应用系统成败的标准。而采用索引来加快数据处理速度也成为广大数据库用户所
- 这篇文章主要介绍了python标识符命名规范原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友
- 一般情况下只有需要长期运行的项目才会去关注内存的增长情况,即使是很小部分的内存泄露经过长期的运行仍然会产生很大的隐患。python本身也是支
- 对数据库的操作无非就是增删改查,其中数查询操作最为复杂,所以将查询单独讲解,我这里用的Mysql数据库增删改查操作分页查询操作1.查询结果以
- 原文地址:30 Days of Mootools 1.2 Tutorials - Day 21 - Classes part
- 最近,我有机会研究对视觉设计作用的常见误解,这些误解仍然盛行于行政主管、产品主管,工程经理和市场专家中。设计团队成员如何说明这些认识是错误的
- 感觉很流畅的键盘控制(带惯性) <body> <div id="man" style="po
- 这是我的数据库student,好比输入一个值为32,查询id最接近32的整行数据,可以用以下代码import pymysqlvalue=32