Django模板中单列多次复用同个表单提交考试成绩的实现方案
用Django原生的FormSet完全可以实现你的需求,默认的表格渲染只是方便快速开发的封装,你完全可以手动控制渲染逻辑实现单列排布,具体实现步骤如下:
1. 定义表单与FormSet
首先给Grade模型创建对应的ModelForm,再基于该表单生成FormSet:
from django import forms from .models import Grade, Exam # 单条成绩录入表单 class GradeForm(forms.ModelForm): class Meta: model = Grade fields = ["student", "subject", "grade"] # 可自定义widget添加前端样式类,适配你的页面UI widgets = { "grade": forms.NumberInput(attrs={"class": "form-control"}), "student": forms.Select(attrs={"class": "form-control"}), "subject": forms.Select(attrs={"class": "form-control"}), } # 生成批量录入的FormSet,extra参数为默认显示的空表单项数量,可按需调整 GradeFormSet = forms.formset_factory(GradeForm, extra=15, can_delete=False)
如果你的业务逻辑里单条成绩仅属于一次考试,建议把Exam和Grade的多对多关联改成Grade里加外键指向Exam,后续可以直接用inlineformset_factory,关联保存逻辑会更简单。
2. 模板自定义渲染实现单列排布
不要用FormSet默认的as_table()、as_p()这类快速渲染方法,手动循环FormSet里的每一个表单,按你的布局要求写结构即可:
<form method="POST" action=""> {% csrf_token %} <!-- 渲染考试本身的字段,比如考试名称、考试时间等 --> <div class="exam-base-info"> {{ exam_form.as_p }} </div> <h4>成绩录入</h4> <!-- FormSet必填的管理表单,必须放在循环前渲染 --> {{ formset.management_form }} <!-- 循环每个成绩表单,每个表单单独占一块实现单列排布 --> {% for grade_form in formset %} <div class="grade-form-item" style="margin: 16px 0; padding: 12px; border: 1px solid #eee; border-radius: 4px;"> {% for field in grade_form %} <div class="form-field" style="margin: 8px 0;"> {{ field.label_tag }} {{ field }} {% if field.errors %} <span style="color: red; font-size: 12px;">{{ field.errors.0 }}</span> {% endif %} </div> {% endfor %} </div> {% endfor %} <button type="submit" style="margin-top: 20px; padding: 8px 16px;">提交全部信息</button> </form>
上面的样式你可以根据自己的需求调整,只要保证每个表单/字段按你要的单列排列即可,完全不受FormSet默认逻辑限制。
3. 视图层处理批量保存逻辑
视图层同时校验考试基础表单和成绩FormSet,校验通过后统一保存即可:
from django.shortcuts import render, redirect from .forms import ExamForm, GradeFormSet def create_exam(request): if request.method == "POST": exam_form = ExamForm(request.POST) grade_formset = GradeFormSet(request.POST) # 同时校验两个表单的合法性 if exam_form.is_valid() and grade_formset.is_valid(): # 先保存考试基础信息 exam = exam_form.save() # 遍历保存所有填写了的成绩 for form in grade_formset: # 跳过用户没填的空行 if form.cleaned_data: grade = form.save() exam.grades.add(grade) return redirect("exam_list") # 跳转到考试列表或者其他目标页 else: exam_form = ExamForm() grade_formset = GradeFormSet() return render(request, "create_exam.html", { "exam_form": exam_form, "formset": grade_formset })
内容的提问来源于stack exchange,提问作者Saman。
相关产品推荐
相关产品推荐

