首先上结论:
form适用于对单个表单的操作,并且需要对每个字段的验证规则自定义。
modelform:适用于对用户提交的单个表单操作,字段可以用model中的表的字段来作为验证规则,适用于快速的进行增加、修改。
formset:适用于对多个表单进行操作,字段需要也可以用model中的表的字段来作为验证规则。
modelfoemset:适用于对多个表单进行操作,字段需要也可以用model中的表的字段来作为验证规则,速度可能快一些(有待考证)
form用法
后端代码
from django.forms import widgets wid_01=widgets.TextInput(attrs="class":"form-control") wid_02=widgets.PasswordInput(attrs="class":"form-control") class UserForm(forms.Form): name=forms.CharField(max_length=32, widget=wid_01 ) pwd=forms.CharField(max_length=32,widget=wid_02) r_pwd=forms.CharField(max_length=32,widget=wid_02) email=forms.EmailField(widget=wid_01) tel=forms.CharField(max_length=32,widget=wid_01) def register(request): if request.method=="POST": form=UserForm(request.POST) if form.is_valid(): print(form.cleaned_data) # 所有干净的字段以及对应的值 else: print(form.cleaned_data) # print(form.errors) # ErrorDict : "校验错误的字段":["错误信息",] print(form.errors.get("name")) # ErrorList ["错误信息",] return HttpResponse("OK") form=UserForm() return render(request,"register.html",locals())
<form action="" method="post"> % csrf_token % % for field in form % <div> <label for=""> field.label </label> field </div> % endfor % <input type="submit" class="btn btn-default pull-right"> </form>
modelform用法
class MenuModelForm(forms.ModelForm): class Meta: model = models.Menu fields = ‘__all__‘ widgets = ‘title‘: forms.TextInput(attrs=‘placeholder‘: ‘请输入角色名称‘, ‘class‘: ‘form-control‘), ‘icon‘: forms.Radioselect( choices=ICON_LIST ) error_messages = ‘title‘: ‘required‘: ‘菜单名称不能为空‘, , ‘icon‘: ‘required‘: ‘请选择图标‘, def menu_add(request): """ 添加菜单 :param request: :return: """ if request.method == ‘GET‘: form = MenuModelForm() else: form = MenuModelForm(request.POST) if form.is_valid(): print(form.data) form.save() return redirect(reverse(‘rbac:menu_list‘)) return render(request, ‘rbac/menu_change.html‘, ‘form‘: form) def menu_edit(request, pk): """ 编辑菜单 :param request: :return: """ obj = models.Menu.objects.filter(id=pk).first() if not obj: return HttpResponse(‘菜单不存在‘) if request.method == ‘GET‘: form = MenuModelForm(instance=obj) return render(request, ‘rbac/menu_change.html‘, ‘form‘: form) form = MenuModelForm(request.POST, instance=obj) if form.is_valid(): form.save() return redirect(reverse(‘rbac:menu_list‘))
<div class="luffy-container"> <form class="form-horizontal" method="post" novalidate> % csrf_token % <div class="form-group"> <label class="col-sm-2 control-label">菜单名称:</label> <div class="col-sm-6"> form.title </div> <div class="col-sm-offset-1 col-sm-2"> <input type="submit" value="保 存" class="btn btn-primary"> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">图标:</label> <div class="col-sm-7 icon-area"> form.icon </div> <div class="col-sm-3"> <div> form.title.errors.0 </div> <div> form.icon.errors.0 </div> </div> </div> </form> </div>
formset用法
class MultiPermissionForm(forms.Form): id = forms.IntegerField( widget=forms.HiddenInput(), required=False ) title = forms.CharField( widget=forms.TextInput(attrs=‘class‘: "form-control") ) url = forms.CharField( widget=forms.TextInput(attrs=‘class‘: "form-control") ) name = forms.CharField( widget=forms.TextInput(attrs=‘class‘: "form-control") ) menu_id = forms.ChoiceField( choices=[(None, ‘-----‘)], widget=forms.Select(attrs=‘class‘: "form-control"), required=False, ) pid_id = forms.ChoiceField( choices=[(None, ‘-----‘)], widget=forms.Select(attrs=‘class‘: "form-control"), 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‘) def clean_pid_id(self): menu = self.cleaned_data.get(‘menu_id‘) pid = self.cleaned_data.get(‘pid_id‘) if menu and pid: raise forms.ValidationError(‘菜单和根权限同时只能选择一个‘) return pid def add(request): """ 增加 :param request: :return: """ MultiPermissionFormSet = formset_factory(MultiPermissionForm, extra=0) if request.method == ‘GET‘: form = MultiPermissionFormSet() return render(request,‘list.html‘,‘form‘:form form = MultiPermissionFormSet(request.post) if form.is_valid(): return redict(‘url‘) else: ......... def edit(request): """ 修改 :param request: :return: """ MultiPermissionFormSet = formset_factory(MultiPermissionForm, extra=0) if request.method == ‘GET‘: form = MultiPermissionFormSet(‘数据‘) # formset是支持批量修改的所以 这里传入的数据一定要是可迭代对象,并且里面的 数据类型是字典或者对象 return render(request,‘list.html‘,‘form‘:form form = MultiPermissionFormSet(request.post) if form.is_valid(): return redict(‘url‘) else: .........
<div class="luffy-container"> <form method="post" action="?type=generate"> % csrf_token % form.management_form # 这里一定要记得写这一步 <div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"> <i class="fa fa-binoculars" aria-hidden="true"></i> 待新建权限列表 <button class="right btn btn-primary btn-xs" style="padding: 2px 8px;margin: -3px;"> <i class="fa fa-save" aria-hidden="true"></i> 新建 </button> </div> <div class="panel-body" style="color: #9d9d9d;"> 注意:路由系统中自动发现且数据库中不存在的路由。 </div> <table class="table table-bordered"> <thead> <tr> <th>序号</th> <th>名称</th> <th>URL</th> <th>别名</th> <th>所属菜单</th> <th>根权限</th> </tr> </thead> <tbody> % for form in generate_formset % <tr> <td style="vertical-align: middle;"> forloop.counter </td> % for field in form % # 这里在渲染标签的时候一定要渲染 id这个标签 这个很重要不然会报错 这里是写了两个fou循环 所以自动渲染了id标签 % if forloop.first % <td class="hide"> % else % <td> % endif % field <span style="color: firebrick;"> field.errors.0 </span> </td> % endfor % % endfor % </tbody> </table> </div> </form>
modelformset用法
class StudyRecordModelForm(forms.ModelForm): class Meta: model = models.StudyRecord fields = [‘student‘,‘record‘,‘score‘,‘homework_note‘] def changelist_view(self,request): ccid = request.GET.get(‘ccid‘) model_formset_cls = modelformset_factory(models.StudyRecord,StudyRecordModelForm,extra=0) queryset = models.StudyRecord.objects.filter(course_record_id=ccid) if request.method == "GET": formset = model_formset_cls(queryset=queryset)
# 这里UI定是个可迭代对象,因为modelformset是操作多表的,里面的数据类型可以为字典或者对象 return render(request,‘study_record.html‘,‘formset‘:formset) formset = model_formset_cls(data=request.POST) print(request.POST) if formset.is_valid(): formset.save() return redirect(‘/stark/crm/studyrecord/list/?ccid=%s‘ %ccid ) return render(request, ‘study_record.html‘, ‘formset‘: formset)
<div class="panel panel-default"> <div class="panel-heading">学习记录</div> <div class="panel-body"> <div style="width: 680px;margin: 0 auto;"> <form method="post"> % 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 # 这里只写了一层for循环,所以手动写字段,必须把id字段写上 <td> form.instance.student </td> <td> form.record form.record.errors.0 </td> <td> form.score form.score.errors.0 </td> <td> form.homework_note form.homework_note.errors.0 </td> </tr> % endfor % </tbody> </table> <input type="submit" value="保存"> </form> </div> </div> </div>
以上为这四种的区别和用法。
以上是关于form modelform formset modelformset的各种用法的主要内容,如果未能解决你的问题,请参考以下文章
formset、inlineformset_Factory 和 kwargs
如何在 django modelform 中的必填字段后添加 *?