Django表单集合----Formset
概述:Formset(表单集)是多个表单的集合。Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息,下面将会详细讲述如何使用Formset。
一、Formset的分类
Django针对不同的formset提供了三种方法:formset_factory,modelformset_factory和inlineformset_factory。
二、如何使用formset_factory
对于继承forms.Form的自定义表单,我们可以使用formset_factory。
#models.py from django import forms class BookForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField()
pub_date = forms.DateField(required=False) # forms.py - build a formset of books from django.forms import formset_factory
from myapp.models import BookForm # extra: 想要显示空表单的数量
# max_num: 表单显示最大数量,可选,默认1000 BookFormSet = formset_factory(BookForm, extra=3, max_num=2)
在视图文件views.py里,我们可以像使用form一样使用formset
# views.py - formsets example. from .forms import BookFormSet
from django.shortcuts import render def manage_books(request):
if request.method == 'POST':
formset = BookFormSet(request.POST)
if formset.is_valid():
# do something with the formset.cleaned_data
pass
else:
formset = BookFormSet()
#如果想传入初始数据可设置initial = [{'name':'python','pub_date':'北京出版社'}]
return render(request, 'manage_books.html', {'formset': formset})
注意:如果使用了 initial 来显示formset,那么您需要在处理formset提交时传入相同的 initial ,以便formset检测用户更改了哪些表单。例如,您可能有这样的: BookFormSet(request.POST, initial=[...])。
模板里可以这样使用formset:
<form action=”.” method=”POST”>
{{ formset }}
</form>
也可以这样使用:
<form method="post">
{{ formset.management_form }} #一定要加这行代码
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
formset_factory()参数解释:
1、如果 max_num 的值大于初始数据现有数量,那空白表单可显示的数量取决于 extra 的数量,只要总表单数不超过 max_num 。例如, extra=2 , max_num=2 并且formset有一个 initial 初始化项,则会显示一张初始化表单和一张空白表单。
2、如果初始数据项的数量超过 max_num ,那么 max_num 的值会被无视,所有初始数据表单都会显示,并且也不会有额外的表单显示。例如,假设 extra=3 , max_num=1 并且formset有两个初始化项,那么只会显示两张有初始化数据的表单。
3、max_num 的值 None (默认值),它限制最多显示(1000)张表单,其实这相当于没有限制。
三、如何使用modelformset_factory
Formset也可以直接由模型model创建,这时你需要使用modelformset_factory。你可以指定需要显示的字段和表单数量。
class StudentStudyRecordModelForm(forms.ModelForm):
class Meta:
model=StudentStudyRecord
fields=["score","homework_note"]
由ModelForm创建formset:
model_formset_cls=modelformset_factory(model=StudentStudyRecord,form=StudentStudyRecordModelForm,extra=0)
views.py
class RecordScoreView(View):
def get(self, request,class_study_record_id):
model_formset_cls=modelformset_factory(model=StudentStudyRecord,form=StudentStudyRecordModelForm,extra=0)
queryset = StudentStudyRecord.objects.filter(classstudyrecord=class_study_record_id)
formset = model_formset_cls(queryset=queryset)
return render(request,"student/record_score.html",locals())
def post(self, request,class_study_record_id):
model_formset_cls = modelformset_factory(model=StudentStudyRecord, form=StudentStudyRecordModelForm, extra=0)
formset=model_formset_cls(request.POST)
if formset.is_valid():
formset.save()
return redirect(request.path)
模板:
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
<table class="table table-bordered">
<thead>
<tr>
<th>姓名</th>
<th>考勤</th>
<th>作业成绩</th>
<th>作业评语</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
{{ form.id }}
<td>{{ form.instance.student }}</td>
<td>{{ form.instance.get_record_display }} </td>
<td>{{ form.score }} </td>
<td>{{ form.homework_note }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="保存">
</form>
四、如何使用inlineformset_factory
试想我们有如下recipe(菜谱)模型,Recipe(菜谱)与Ingredient(原料)是一对多的关系。一般的formset只允许我们一次性提交多个Recipe或多个Ingredient。但如果我们希望同一个页面上添加一个菜谱(Recipe)和多个原料(Ingredient),这时我们就需要用使用inlineformset了。
from django.db import models class Recipe(models.Model):
title = models.CharField(max_length=255)
description = models.TextField() class Ingredient(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name='ingredient')
name = models.CharField(max_length=255)
利用inlineformset_factory创建formset的方法如下所示。该方法的第一个参数和第二个参数都是模型,其中第一个参数必需是ForeignKey。
# forms.py from django.forms import ModelForm
from django.forms import inlineformset_factory from .models import Recipe, Ingredient, Instruction class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ("title", "description",) IngredientFormSet = inlineformset_factory(Recipe, Ingredient, fields=('name',),
extra=3, can_delete=False, max_num=5)
views.py中使用formset创建和更新recipe(菜谱)的代码如下。在对IngredientFormSet进行实例化的时候,必需指定recipe的实例。
def recipe_update(request, pk): #更新
recipe = get_object_or_404(Recipe, pk=pk)
if request.method == "POST":
form = RecipeForm(request.POST, instance=recipe) if form.is_valid():
recipe = form.save()
ingredient_formset = IngredientFormSet(request.POST, instance=recipe) if ingredient_formset.is_valid():
ingredient_formset.save() return redirect('/recipe/')
else:
form = RecipeForm(instance=recipe)
ingredient_formset = IngredientFormSet(instance=recipe) return render(request, 'recipe/recipe_update.html', {'form': form,
'ingredient_formset': ingredient_formset,
}) def recipe_add(request): #创建
if request.method == "POST":
form = RecipeForm(request.POST) if form.is_valid():
recipe = form.save()
ingredient_formset = IngredientFormSet(request.POST, instance=recipe) if ingredient_formset.is_valid():
ingredient_formset.save() return redirect('/recipe/')
else:
form = RecipeForm()
ingredient_formset = IngredientFormSet() return render(request, 'recipe/recipe_add.html', {'form': form,
'ingredient_formset': ingredient_formset,
})
模板recipe/recipe_add.html代码如下:
<h1>Add Recipe</h1>
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<fieldset>
<legend>Recipe Ingredient</legend>
{{ ingredient_formset.management_form }}
{{ ingredient_formset.non_form_errors }}
{% for form in ingredient_formset %}
{{ form.name.errors }}
{{ form.name.label_tag }}
{{ form.name }}
</div>
{% endfor %}
</fieldset> <input type="submit" value="Add recipe" class="submit" />
</form>
Django表单集合----Formset的更多相关文章
- python 全栈开发,Day111(客户管理之 编辑权限(二),Django表单集合Formset,ORM之limit_choices_to,构造家族结构)
昨日内容回顾 1. 权限系统的流程? 2. 权限的表有几个? 3. 技术点 中间件 session orm - 去重 - 去空 inclusion_tag filter 有序字典 settings配置 ...
- Django表单集合Formset的高级用法
Formset(表单集)是多个表单的集合.Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息.今天小编我就介绍下Djang ...
- python3之Django表单(一)
1.HTML中的表单 在HTML种,表单是在<form>...</form>种的元素,它允许用户输入文本,选择选项,操作对象等,然后发送这些数据到服务器 表单元素允许用户在表单 ...
- 在一般处理程序中,把Form Post过来的表单集合转换成对象 ,仿 MVC post,反射原理
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.L ...
- django表单的api
django表单的api,参考文档:https://yiyibooks.cn/xx/Django_1.11.6/ref/forms/api.html 绑定与未绑定形式: Form要么是绑定的,要么是未 ...
- Django表单API详解
声明:以下的Form.表单等术语都指的的广义的Django表单. Form要么是绑定了数据的,要么是未绑定数据的. 如果是绑定的,那么它能够验证数据,并渲染表单及其数据,然后生成HTML表单.如果未绑 ...
- 9:django 表单
django自带表单系统,这个表单系统不仅可以定义属性名,还可以自己定义验证,更有自己自带的错误提示系统 这节我们仅仅粗略的来看一下django表单系统的入门运用(具体的实在太多东西,主要是我觉得有很 ...
- django 表单系统 之 forms.Form
继承forms.Form实现django表单系统 参考: https://www.cnblogs.com/zongfa/p/7709639.html https://www.cnblogs.com/c ...
- 关于创建Django表单Forms继承BaseForm的问题
在创建Django表单时,因为需要验证用户输入的验证码是否正确,因此需要在session里提取当前验证码的值和POST提交过来的值进行比对,如图: form.py from django import ...
随机推荐
- SD-WAN 配置及应用模板**(二)
目录 0. 前言 1. 配置模板 1.1 创建各类 'Feature' 模板: 1.1.1 添加波特率模板 1.1.2 添加 'VPN0' 模板 1.1.3 添加 'VPN10' 模板 1.1.4 添 ...
- SUSE Ceph 增加节点、减少节点、 删除OSD磁盘等操作 - Storage6
一.测试环境描述 之前我们已快速部署好一套Ceph集群(3节点),现要测试在现有集群中在线方式增加节点 如下表中可以看到增加节点node004具体配置 主机名 Public网络 管理网络 集群网络 说 ...
- 架构——android架构演进概述
随着业务的发展和技术的变更,Android开发也经历了以下几个发展阶段: 看似高大上的名词,其实遵循着最简单的原则:分而治之(如何划分就是"架构",简单的事情如何串在一起就是&qu ...
- 快学Scala 第二十二课 (apply和unapply)
apply和unapply: apply方法经常用在伴生对象中,用来构造对象而不用显式地使用new. unapply是当做是伴生对象的apply方法的反向操作.apply方法接受构造参数,然后将他们变 ...
- iOS渠道分包2种模式之包内注入文件分包
解决问题:商业模式中会存在这样的形式1款app需要不同的运用团队(工会)去分包推广,谁推广的包下载的人数都会在服务器记录,不同渠道的标示唯一来区分. iOS渠道分包模式有两种 一.IDFA模式 IDF ...
- Flutter学习笔记(29)--Flutter如何与native进行通信
如需转载,请注明出处:Flutter学习笔记(29)--Flutter如何与native进行通信 前言:在我们开发Flutter项目的时候,难免会遇到需要调用native api或者是其他的情况,这时 ...
- .NET斗鱼直播弹幕客户端(上)
现在直播平台由于弹幕的存在,主播与观众可以更轻松地进行互动,非常受年轻群众的欢迎.斗鱼TV就是一款非常流行的直播平台,弹幕更是非常火爆.看到有不少主播接入弹幕语音播报器.弹幕点歌等模块,这都需要首先连 ...
- 智慧金融时代,大数据和AI如何为业务赋能
前言:宜信技术人物专访是宜信技术学院推出的系列性专题,我们邀请软件研发行业的优秀技术人,分享自己在软件研发领域的实践经验和前瞻性观点. 第一期专访我们邀请到宜信科技中心AI中台负责人王东老师,从大数据 ...
- Linux入门(服务)
LInux入门之 服务 服务介绍 常驻在内存中的程序,且可以提供一些系统或网络功能,那就是服务.比如: apache提供web服务 ftp提供文件下载上传服务 ssh提供了远程连接服务 防火墙提供了安 ...
- 继续学习freertos消息队列
写在前面:杰杰这个月很忙~所以并没有时间更新,现在健身房闭馆装修,晚上有空就更新一下!其实在公众号没更新的这段日子,每天都有兄弟在来关注我的公众号,这让我受宠若惊,在这里谢谢大家的支持啦!!谢谢^ 在 ...