如何为外键关联的两个模型创建单表单?修复Django投票系统IntegrityError
问题分析
你遇到的IntegrityError本质是Choice模型的question外键字段未赋值,核心原因有三点:
- 保存Choice时,没有关联刚创建的Question实例,数据库要求这个外键必须存在有效关联,因此触发完整性校验错误。
- 模板里重复渲染同一个
addChoiceForm,提交时多个选项的表单字段名完全一致,后端无法区分不同选项,也没法批量处理。 - 视图逻辑里只处理了单个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
相关产品推荐
相关产品推荐

