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

如何为外键关联的两个模型创建单表单?修复Django投票系统IntegrityError

问题分析

你遇到的IntegrityError本质是Choice模型的question外键字段未赋值,核心原因有三点:

  1. 保存Choice时,没有关联刚创建的Question实例,数据库要求这个外键必须存在有效关联,因此触发完整性校验错误。
  2. 模板里重复渲染同一个addChoiceForm,提交时多个选项的表单字段名完全一致,后端无法区分不同选项,也没法批量处理。
  3. 视图逻辑里只处理了单个Choice,和你要提交多个选项的需求不匹配。
修复步骤

1. 修改forms.py,用表单集处理多个选项

Django的表单集(FormSet)支持批量处理同类型表单,替换原来的单个Choice表单:

from django.forms import ModelForm, modelformset_factory
from .models import Question, Choice

class addPollsForm(ModelForm):
    class Meta:
        model = Question
        fields = ['question_text', 'pub_date', ]

# 创建Choice的表单集,配置对应需求的选项数量
ChoiceFormSet = modelformset_factory(
    Choice,
    fields=['choice_text'],
    extra=3,  # 默认显示3个空选项表单
    min_num=1,  # 要求至少填写1个选项
    validate_min=True
)

2. 修改views.py,关联Question与Choice

先保存Question实例,再将每个Choice关联到该实例后完成保存:

def addPollsPage(request):
    if request.user.is_authenticated:
        formAddPolls = addPollsForm()
        # 初始化表单集,queryset设为空避免加载已有选项
        formset = ChoiceFormSet(queryset=Choice.objects.none())

        if request.method == 'POST':
            formAddPolls = addPollsForm(request.POST)
            formset = ChoiceFormSet(request.POST)
            
            if formAddPolls.is_valid() and formset.is_valid():
                # 先保存Question,获取实例对象
                question = formAddPolls.save()
                # 遍历表单集,为每个Choice关联Question后保存
                for form in formset:
                    if form.cleaned_data:  # 跳过未填写的空表单
                        choice = form.save(commit=False)
                        choice.question = question
                        choice.save()
                return redirect('votacao:index')

        context = {
            'formAddPolls': formAddPolls,
            'formset': formset
        }
        return render(request, 'votacao/addPolls.html', context)
    else:
        return redirect('main')

3. 修改addPolls.html模板,渲染表单集

替换原来重复的formAddChoice为表单集的标准渲染方式:

<form action="" method="POST">
    {% csrf_token %}
    {{ formAddPolls.as_p }}
    {{ formset.management_form }}  <!-- 必须添加,表单集的管理字段,Django用于跟踪表单状态 -->
    {% for form in formset %}
        {{ form.as_p }}
    {% endfor %}
    <br>
    <input type="submit" name="Submit">
</form>
额外说明
  • commit=False用于先创建Choice实例但不立即写入数据库,等关联Question后再执行保存操作。
  • 可根据需求调整表单集的extra(默认空表单数量)、min_num(必填选项数量)参数。

内容的提问来源于stack exchange,提问作者Eduardo Brandão

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:57:14