Django Form 实现多层(嵌套)模型表单
在 Django 中,可以通过使用 ModelForm
和 InlineFormSet
来实现多层(嵌套)模型表单。这样可以在一个表单中同时编辑主模型及其相关的子模型。下面是一个示例,演示如何实现这种多层嵌套的表单。
1、问题背景
- 如何使用 Django 的 Form 来创建涉及多个模型的多层嵌套表单?
- 在 Django 初学者使用 Form 时遇到了错误“invalid literal for int() with base 10: ‘test’”。
- 需要创建涉及多个模型的表单,例如“测验-问题-答案”模型,并且每个测验包含多个问题,每个问题有多个答案。
2、解决方案
- 方法一
- 使用 Django 的 ModelForm 来创建各个模型的表单。
- 手动将这些表单组合成一个多层表单。
- 需要考虑保存数据的顺序,即先保存最底层的模型,然后是中间层的模型,最后是顶层的模型。
- 方法二
- 使用 Django 的
InlineFormSet
和ModelForm
来创建多层表单。 InlineFormSet
可以用来创建嵌套的表单集,其中每个表单集对应一个模型。ModelForm
可以用来创建单个模型的表单。- 将这些表单集和表单组合在一起,就可以生成一个多层表单。
- 使用 Django 的
代码示例
方法一:手动组合表单
from django.forms import ModelForm, Form
class QuizForm(ModelForm):
class Meta:
model = Quiz
class QuestionForm(ModelForm):
class Meta:
model = Question
class AnswerForm(ModelForm):
class Meta:
model = Answer
class MultiLayerForm(Form):
quiz_form = QuizForm()
question_forms = QuestionFormSet(queryset=Question.objects.filter(quiz=None))
answer_forms = AnswerFormSet(queryset=Answer.objects.filter(question=None))
def view_function(request):
if request.method == 'POST':
quiz_form = QuizForm(request.POST)
question_forms = QuestionFormSet(request.POST, queryset=Question.objects.filter(quiz=None))
answer_forms = AnswerFormSet(request.POST, queryset=Answer.objects.filter(question=None))
if quiz_form.is_valid() and all(form.is_valid() for form in question_forms) and all(form.is_valid() for form in answer_forms):
# Save the forms
quiz = quiz_form.save()
for question_form in question_forms:
question = question_form.save(commit=False)
question.quiz = quiz
question.save()
for answer_form in answer_forms:
answer = answer_form.save(commit=False)
answer.question = question
answer.save()
return HttpResponseRedirect('/')
else:
quiz_form = QuizForm()
question_forms = QuestionFormSet(queryset=Question.objects.filter(quiz=None))
answer_forms = AnswerFormSet(queryset=Answer.objects.filter(question=None))
return render(request, 'form.html', {'quiz_form': quiz_form, 'question_forms': question_forms, 'answer_forms': answer_forms})
方法二:使用 InlineFormSet
和 ModelForm
from django.forms import ModelForm, inlineformset_factory
class QuizForm(ModelForm):
class Meta:
model = Quiz
QuestionFormSet = inlineformset_factory(Quiz, Question, fields=('label',))
AnswerFormSet = inlineformset_factory(Question, Answer, fields=('label', 'correct'))
def view_function(request):
if request.method == 'POST':
quiz_form = QuizForm(request.POST)
question_forms = QuestionFormSet(request.POST, instance=quiz_form.instance)
answer_forms = AnswerFormSet(request.POST, instance=question_forms.instance)
if quiz_form.is_valid() and all(form.is_valid() for form in question_forms) and all(form.is_valid() for form in answer_forms):
# Save the forms
quiz = quiz_form.save()
question_forms.save()
answer_forms.save()
return HttpResponseRedirect('/')
else:
quiz_form = QuizForm()
question_forms = QuestionFormSet(instance=quiz_form.instance)
answer_forms = AnswerFormSet(instance=question_forms.instance)
return render(request, 'form.html', {'quiz_form': quiz_form, 'question_forms': question_forms, 'answer_forms': answer_forms})
通过上述步骤,你可以创建一个嵌套的表单界面,使得用户可以在同一页面上输入主模型及其相关子模型的信息。这种方法非常适合需要处理多层数据结构的应用场景。