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
相关产品推荐
相关产品推荐

