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

Django Formset提交健身准备度问卷外键报错问题咨询

问题根因
  • 方案一报错:你将外键类型的readiness_question字段强行改为CharField,提交时传入的是问题名称字符串,无法直接赋值给外键字段,必须传入ReadinessQuestion实例
  • 方案二校验失败:模板中未渲染readiness_question对应的输入控件,提交时该字段无值,触发必填校验错误
  • 原有视图逻辑缺陷:无论表单是否校验通过都先创建Workout实例,会生成无效垃圾数据
修复方案

1. 修改forms.py

保留外键字段的原有类型,仅将控件设为隐藏,自动存储问题ID:

class WorkoutReadinessForm(forms.ModelForm):
    class Meta:
        model  = WorkoutReadiness
        fields = ['readiness_question', 'rating',]
        widgets = {
            # 隐藏问题字段,仅存ID
            'readiness_question': forms.HiddenInput()
        }

WRFormSet = forms.formset_factory(WorkoutReadinessForm, extra=0)

2. 修改模板文件

显式渲染隐藏的问题字段,保证提交时参数完整:

<table>
  <form action="" method="post">
    {% csrf_token %}
    {{ formset.management_form }}
    {% for form in formset %}
      <tr>
        <td>{{ form.initial.readiness_question }}</td> 
        <td>{{ form.rating }}</td> 
        <!-- 新增这一行,渲染隐藏的问题ID输入框 -->
        <td>{{ form.readiness_question }}</td>
      </tr>
    {% endfor %}
    {% if formset.errors %}
    <tr>
      <td colspan="3" style="color:red;">表单填写有误,请检查后重试</td>
    </tr>
    {% endif %}
    <button type="submit" class="btn btn-outline-primary">Submit</button>
  </form>
</table>

3. 修改视图逻辑

调整执行顺序,校验通过后再创建Workout,使用批量插入提升效率:

def create_workoutreadiness(request):
    questions = ReadinessQuestion.objects.all()
    initial_data = [{'readiness_question':q} for q in questions]
    
    if request.method == 'POST':
        formset = WRFormSet(request.POST)
        # 先校验表单,校验通过再创建数据
        if formset.is_valid():
            workout = Workout.objects.create(user=request.user)
            readiness_list = []
            for form in formset:
                wr = form.save(commit=False)
                wr.workout = workout
                readiness_list.append(wr)
            # 批量插入答题记录,减少数据库请求次数
            WorkoutReadiness.objects.bulk_create(readiness_list)
            return HttpResponseRedirect(reverse_lazy('routines:workout_exercise_list', kwargs={'pk':workout.id}))
    else:
        formset = WRFormSet(initial=initial_data)
    
    context = {
        'formset':formset,
    }
    return render(request, 'routines/workout_readiness/_form.html', context)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:18:02