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
猜你喜欢
- 成天都要与样式打交道的朋友,相信对CSS选择符(CSS Selectors)都不会陌生。不过对于刚接触或者还不是很熟悉css的朋友来说,能够
- 国 * 公司安全团队开发出利用赛门铁克数据库安全与审计(SDSA)设备监视数据库的一系列客户化的政策。他们是如何在已有安全策略基础上做优
- 每个矿工将从先前创建的交易池中获取交易.要跟踪已挖掘的消息数量,我们必须创建一个全局变量 :last_transaction_index =
- python如何将json格式的数据快速的转化成指定格式的数据呢?或者转换成sql文件?下面的例子是将json格式的数据准换成以#_#分割的
- 我就废话不多说了,大家还是直接看代码吧!# -*- coding: utf-8 -*-"""Created o
- 比如:import linecacheprint linecache.getline('2.1_open.py&
- php获取 checkbox复选框值的方法 <html xmlns="https://www.aspxhome.net/19
- <html><head>//搜索暂时没做,数据是出来了,但是却没法显示<link rel="styl
- 第一步:升级pythonCentOs 6.x的系统默认安装的Python版本是2.6.x,想升级到Python2.7.x,从官方下载源文件,
- Python 是由吉多·范罗苏姆(Guido Van Rossum)在 90 年代早期设计。 它是如今最常用的编程语言之一。它的语法简洁且优
- 如下所示:import pandas as pdpath='F:/python/python数据分析与挖掘实战/图书配套数据、代码/
- 我们开发数据库应用时,常常需要用到模糊查询。如果同一个条件需要匹配很多字段怎么办呢?通常,程序员会每个字段都在SQL中“field like
- class Helper_Page{ /** 总信息数 */ var $infoCount; /** 总页数 */ var $pageCou
- Python是一门非常适合处理数据和自动化完成重复性工作的编程语言,我们在用数据训练机器学习模型之前,通常都需要对数据进行预处理,而Pyth
- 先介绍一下redis的pub/sub功能:Pub/Sub功能(means Publish, Subscribe)即发布及订阅功能。基于事件的
- 如下所示:import osimport shutil#path of imgrpath = 'D:\\BaiduNetdiskDo
- //-------------------------------------------- // 删除千分点。 //-----------
- 前言飞桨(PaddlePaddle)是集深度学习核心框架、工具组件和服务平台为一体的技术先进、功能完备的开源深度学习平台1. 任务描述乘坐出
- 本文实例讲述了python实现的config文件读写功能。分享给大家供大家参考,具体如下:1、设置配置文件[mysql]host = 123
- 本文实例讲述了Python 私有化操作。分享给大家供大家参考,具体如下:私有化xx: 公有变量_x: 单前置下划线,私有化属性或方法,fro