formset批量处理form表单数据

Formset(表单集)是多个表单的集合。Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据

class StudentStudyRecordModel(forms.ModelForm):
    class Meta:
        model=StudentStudyRecord
        fields=['score','homework_note']

view视图

from django.forms.models import modelformset_factoryclass Student_study_record(View):
def get(self,request):
        model_formset_cls=modelformset_factory(model=StudentStudyRecord,form=StudentStudyRecordModel,extra=0)
        queryset=StudentStudyRecord.objects.filter(classstudyrecord__id=request.GET.get('pk')) #批量操作的queryset
        formset=model_formset_cls(queryset=queryset)
        return render(request, 'students/Student_study_record.html', locals())

    def post(self,request):
        model_formset_cls = modelformset_factory(model=StudentStudyRecord, form=StudentStudyRecordModel, extra=0)
        formset=model_formset_cls(request.POST)  #与modelform校验基本一致,就是不用穿instance了
        if formset.is_valid():
            formset.save()
            return redirect('/class_study_record/')
        else:
            print('formset.errors##################',formset.errors)
            return self.get(request)

templates模版

<form action="" method="post" novalidate>

                <table class="table table-hover table-striped" style="margin-top: 20px">
                    <thead>
                        <tr>
                            <td>编号</td>
                            <td>姓名</td>
                            <td>考勤</td>
                            <td>成绩</td>
                            <td>批语</td>
                        </tr>
                    </thead>
                    <tbody>
{#                     必须有,不然会报错#}
                    {{ formset.management_form }}
                    {% for form in formset %}
                        <tr>
                            <td>{{ form.id }}</td>           # 必须有form.id
                            <td>{{ form.instance.student }}</td>    #instance是显示具体的某个对象的值,而不是多选框(不能修改)
                            <td>{{ form.instance.get_record_display }}</td>  
                            <td>{{ form.score }}</td>
                            <td>{{ form.homework_note }}</td>
                            {% csrf_token %}
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
                <button class=" btn btn-success btn-sm pull-right" style="margin: 30px;">提交</button>
            </form>

Formset

多个表单的集合,可以同时提交多个from表单中的数据,在web页面中,可以在同一个页面,提交多个form表单。

Django针对不同的formset提供了3种方法: formset_factory, modelformset_factory和inlineformset_factory。下面对modelformset_factory进行示例展示

主要的变化是在视图函数中

from django.forms import modelformset_factory

def study_record(request,courserecord_id):
    # modelformset_factory 支持在同一页面显示多个form,一个form就是作为一条记录,可以直接在本也米娜对from中的内容进行修改
    formset = modelformset_factory(model=models.StudyRecord,form=StudyRecordForm,extra=0)
    formset_obj = formset(queryset=models.StudyRecord.objects.filter(course_record_id=courserecord_id))

    if request.method == 'POST':
        formset_obj = formset(data=request.POST)
        if formset_obj.is_valid():
            formset_obj.save()
            next = request.GET.get('next')
            print(next)
            return redirect(next)

    return render(request,'teacher/studyrecord_list.html',{'formset_obj':formset_obj})
    
 【注意】
 初始化fromset时,使用的参数:model;form;extra=0,等于1时,会有一个额外的空选项
 实例化fromset时,使用的参数:queryset

ModelForm中

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 自定义操作,循环添加class操作,当遇到MultiSelectFormField或者forms.BooleanField框时,不加class类
        for name, field in self.fields.items():
            # if name == 'course'  # 可以直接判断字段名
            if isinstance(field, (MultiSelectFormField, forms.BooleanField)):
                # 判断字段类型是MultiSelectFormField, forms.BooleanField还可以根据需求继续添加到元组中,让他们的格式不接受form-control的样式
                continue
            # 方式一:
            field.widget.attrs['class'] = 'form-control'
            # 方式二:
            # field.widget.attrs.update({'class': 'form-control'})
            
class StudyRecordForm(BaseForm):
    class Meta:
        model = models.StudyRecord
        fields = '__all__'

html中注意`{{ formset_obj.management_form }}`

<form action="" method="post">

        {% csrf_token %}

        {{ formset_obj.management_form }}


        <div>
            <button class="btn btn-primary btn-sm">保存</button>
        </div>

        <table class="table table-hover" id="tableList">
            <thead>
            <tr>
                <th>序号</th>
                <th>学生姓名</th>
                <th>考勤</th>
                <th>成绩</th>
                <th>批语</th>
            </tr>
            </thead>
            <tbody id="UserList">
            {% for obj in formset_obj %}
                <tr class="relative" data-id="3">
                    {{ obj.id }}
                    <td class="table-edit">{{ forloop.counter }} </td>
                    <td class="table-edit">{# 让姓名编程不可修改项  #}
                        <a href=""> {{ obj.instance.student }}</a>
                    </td>
                    <td>{{ obj.attendance }}</td>
                    <td class="table-edit">{{ obj.score }}</td>
                    <td class="table-edit">{{ obj.homework_note }}</td>
                    <td class="hidden">{{ obj.course_record }}</td>
                    <td class="hidden">{{ obj.student }}</td>
                    {# 这两项隐藏的目的是,form表单提交数据时需要对其进行验证,二是不需要让使用者看见,因为他是默认的,不需要跟进修改             #}
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </form>

 

posted @ 2023-03-11 02:29  布衣梦蝶1978  阅读(77)  评论(0编辑  收藏  举报