Django Formset无法保存JS新增表单数据至数据库的问题
问题描述
- 使用Formset默认渲染2个表单,通过JavaScript新增2个表单后总数为4个。
- POST请求后,仅前2个表单数据存入数据库,新增的2个数据未保存。
代码片段
forms.py
class AddAnswerForm(ModelForm): class Meta: model = Answer exclude = ['question'] widgets = { 'answer_text': forms.TextInput(attrs={'class': 'input'}), } AnswerFormSet = modelformset_factory(Answer, form=AddAnswerForm, extra=2, max_num=4)
JavaScript代码(新增表单)
<script> let answerForm = document.querySelectorAll(".answer-form") let container = document.querySelector("#question-form") let addButton = document.querySelector("#add-form") let totalForms = document.querySelector("#id_form-TOTAL_FORMS") let formNum = answerForm.length-1 addButton.addEventListener('click', addForm) function addForm(e){ e.preventDefault() let newForm = answerForm[0].cloneNode(true) let formRegex = RegExp(`form-(\\d){1}-`, 'g') formNum++ newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form=${formNum}-`) container.insertBefore(newForm, addButton) totalForms.setAttribute('value', `${formNum+1}`) } </script>
视图代码
class QuestionAddView(View): form_class = NewQuestionForm form_class_for_answers = AnswerFormSet template_name = 'questions/question_add.html' def get(self, request, *args, **kwargs): form = self.form_class() answers_form = self.form_class_for_answers(queryset=Answer.objects.none()) return render(request, self.template_name, {'form': form, 'answers_form': answers_form}) def post(self, request, *args, **kwargs): form = self.form_class(request.POST, request.FILES) answers_form = self.form_class_for_answers(request.POST) print(request.POST) if form.is_valid() and answers_form.is_valid(): new_question = form.save(commit=False) new_question.author = request.user new_question.save() print(answers_form) instances = answers_form.save(commit=False) print(instances) for instance in instances: print(instance) instance.question = new_question instance.save() return HttpResponseRedirect('/')
打印信息
print(request.POST)输出:
<QueryDict: {'csrfmiddlewaretoken': ['eTaR0N4LgG1WvfK3zshqOcEMYUMvXWkxctfS6OXD9E2rMbMe5VrlTVsBgnjoM2zd'], 'title': ['321321'], 'picture': [''], 'body': ['123123'], 'difficulty': ['None'], 'answer_explanation': ['12321'], 'form-TOTAL_FORMS': ['4'], 'form-INITIAL_FORMS': ['0'], 'form-MIN_NUM_FORMS': ['0'], 'form-MAX_NUM_FORMS': ['4'], 'form-0-answer_text': ['orage'], 'form-0-id': [''], 'form-1-answer_text': ['apple'], 'form-1-id': [''], 'form=2-answer_text': ['grapes'], 'form=2-id': [''], 'form=3-answer_text': ['pear'], 'form=3-id': ['']}>
print(instances)输出:
[<Answer: orage>, <Answer: apple>]
错误原因
从request.POST的输出能明显看到,新增表单的字段名是form=2-answer_text、form=3-answer_text,但Django Formset要求的字段名格式是form-<index>-<field>(比如form-2-answer_text)。问题出在JavaScript的替换逻辑里,把字段名中的减号-误写成了等于号=,导致Formset无法识别这些新增字段。
修复方案
修改JavaScript中替换字段名的代码,将form=${formNum}-改为form-${formNum}-:
function addForm(e){ e.preventDefault() let newForm = answerForm[0].cloneNode(true) let formRegex = RegExp(`form-(\\d){1}-`, 'g') formNum++ // 修正字段名格式:把等于号改成减号 newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`) container.insertBefore(newForm, addButton) totalForms.setAttribute('value', `${formNum+1}`) }
修改后,新增表单的字段名会变成符合要求的form-2-answer_text、form-3-answer_text,Django Formset就能正确识别并处理这些数据,最终将所有表单内容保存到数据库中。
内容的提问来源于stack exchange,提问作者Ivory Leaf
相关产品推荐
相关产品推荐

