You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 23:18:02