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

Django中如何通过单个ModelForm同时创建Quiz及关联Question、Choice多条记录

实现方案

完全有可行方案,Django原生能力即可实现,不需要引入第三方依赖。需要注意的是,原生单个ModelForm仅支持处理单模型的增改操作,你这种三层关联的嵌套数据创建,搭配表单集合(Formset)或者手动处理层级提交逻辑即可满足需求,具体实现如下:


1. 定义基础表单类

首先创建Quiz的基础ModelForm用于处理主表数据:

from django import forms
from .models import Quiz, Question, Choice

class QuizForm(forms.ModelForm):
    class Meta:
        model = Quiz
        fields = ['name', 'description', 'num_questions', 'slug', 'img']

如果需要内置的表单验证、错误提示能力,可额外定义Question和Choice的表单集合,避免手动拼接参数:

# 题目表单
class QuestionForm(forms.ModelForm):
    class Meta:
        model = Question
        exclude = ['quiz']

# 固定生成10个题目的表单集合
QuestionFormSet = forms.formset_factory(
    QuestionForm,
    extra=10,
    max_num=10,
    can_delete=False
)

# 选项表单
class ChoiceForm(forms.ModelForm):
    class Meta:
        model = Choice
        exclude = ['question']

# 每个题目固定生成4个选项的表单集合
ChoiceFormSet = forms.formset_factory(
    ChoiceForm,
    extra=4,
    max_num=4,
    can_delete=False
)

2. 视图层核心逻辑

核心逻辑为先保存Quiz主记录拿到主键,再依次关联保存Question和Choice,自动完成外键赋值,这里给出最易理解的手动处理版本示例:

from django.shortcuts import render, redirect

def create_quiz(request):
    if request.method == 'POST':
        quiz_form = QuizForm(request.POST)
        if quiz_form.is_valid():
            # 第一步:保存Quiz主记录
            quiz = quiz_form.save()
            # 第二步:循环创建10个关联的题目
            for q_idx in range(10):
                question = Question.objects.create(
                    quiz=quiz,
                    content=request.POST.get(f'question_{q_idx}_content', ''),
                    img=request.POST.get(f'question_{q_idx}_img', '')
                )
                # 第三步:给当前题目创建4个关联的选项
                for c_idx in range(4):
                    Choice.objects.create(
                        question=question,
                        content=request.POST.get(f'question_{q_idx}_choice_{c_idx}_content', ''),
                        correct=request.POST.get(f'question_{q_idx}_choice_{c_idx}_correct') == 'on'
                    )
            # 自定义保存成功后的跳转逻辑
            return redirect('quiz_list')
    else:
        quiz_form = QuizForm()
    
    return render(request, 'create_quiz.html', {
        'quiz_form': quiz_form,
        'question_count': 10,
        'choice_per_question': 4
    })

3. 模板层表单渲染

直接按层级渲染对应字段即可,示例代码如下:

<form method="post">
    {% csrf_token %}
    <!-- 渲染Quiz基础字段 -->
    {{ quiz_form.as_p }}

    <!-- 渲染10个题目输入项 -->
    <h3>测验题目</h3>
    {% for q in question_count|rjust:question_count|make_list %}
        <div style="margin: 20px 0; padding: 10px; border: 1px solid #eee;">
            <h4>第{{ forloop.counter }}题</h4>
            <p>
                <label>题目内容:</label>
                <input type="text" name="question_{{ forloop.counter0 }}_content" required maxlength="200">
            </p>
            <p>
                <label>题目图片链接(选填):</label>
                <input type="url" name="question_{{ forloop.counter0 }}_img">
            </p>

            <!-- 渲染当前题目的4个选项 -->
            <div style="margin-left: 20px;">
                <h5>选项</h5>
                {% for c in choice_per_question|rjust:choice_per_question|make_list %}
                    <div style="margin: 10px 0;">
                        <p>
                            <label>选项{{ forloop.counter }}内容:</label>
                            <input type="text" name="question_{{ forloop.parentloop.counter0 }}_choice_{{ forloop.counter0 }}_content" required maxlength="200">
                        </p>
                        <p>
                            <label>是否为正确答案:</label>
                            <input type="checkbox" name="question_{{ forloop.parentloop.counter0 }}_choice_{{ forloop.counter0 }}_correct">
                        </p>
                    </div>
                {% endfor %}
            </div>
        </div>
    {% endfor %}

    <button type="submit">创建测验</button>
</form>

内容的提问来源于stack exchange,提问作者Lumiobyte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 01:15:06