Django嵌套表单集动态添加表单

Django nested formsets adding forms dynamically

我正在尝试使用 Django 创建一个调查页面,该页面具有动态添加问题和选项(针对每个问题)的功能。我有以下三个模型 类:调查、问题和选​​择。

我做了很多研究来弄清楚如何着手实现表单,似乎使用 inline_formsets 的嵌套表单集是正确的方法(I used this tutorial). However, I can't figure out how to add questions and choices dynamically with nested formsets.The JavaScript library that I'm trying to use(This library)没有示例对于嵌套的表单集,我不确定它是否支持它。 这段代码是我目前所拥有的:

forms.py

from django.forms import BaseInlineFormSet
from django.forms import HiddenInput
from django.forms import inlineformset_factory
from django.forms import ModelForm

from .models import *


class SurveyForm(ModelForm):
    class Meta:
        model = Survey
        fields = [
            'name',
            'description',
        ]


class BaseQuestionFormset(BaseInlineFormSet):

    def add_fields(self, form, index):
        super(BaseQuestionFormset, self).add_fields(form, index)
        form.nested = QuestionChoiceFormset(
            instance=form.instance,
            data=form.data if form.is_bound else None,
            files=form.files if form.is_bound else None)

    def is_valid(self):
        result = super(BaseQuestionFormset, self).is_valid()
        print(result)
        if self.is_bound:
            for form in self.forms:
                if hasattr(form, 'nested'):
                    result = result and form.nested.is_valid()

        return result

    def save(self, commit=True):
        for form in self.forms:
            form.save(commit=commit)
        result = super(BaseQuestionFormset, self).save(commit=commit)

        for form in self.forms:
            if hasattr(form, 'nested'):
                if not self._should_delete_form(form):
                    form.nested.save(commit=commit)

        return result


QuestionFormset = inlineformset_factory(
    parent_model=Survey, model=Question, fields='__all__',
    formset=BaseQuestionFormset, extra=1)
QuestionChoiceFormset = inlineformset_factory(
    parent_model=Question, model=Choice,
    fields='__all__', extra=1)

views.py

@login_required
def create(request):
    survey = Survey()
    if request.method == 'POST':
        survey_form = SurveyForm(request.POST, instance=survey)
        question_formset = QuestionFormset(
            request.POST, prefix='questions', instance=survey)

        if survey_form.is_valid() and question_formset.is_valid():
            survey_form.save()
            question_formset.save()
            # url = '/preview/{}'.format(survey.pk)
            # return HttpResponseRedirect(url)
    else:
        survey_form = SurveyForm(instance=survey)
        question_formset = QuestionFormset(instance=survey, prefix='questions')

    context = {
        'survey_form': survey_form,
        'question_formset': question_formset,
    }

    return render(request, 'surveys/create.html', context)

create.html

{% extends 'surveys/base.html' %}
{% load static %}
{% block container %}
<div class="container">
  <h1> Create New Survey </h1>
  <form method="post">
    {% csrf_token %}
    {{ question_formset.management_form }}
    {{ question_formset.non_form_errors }}
    {{ survey_form.as_p }}
    <table id='myForm1'>
      {% for question_form in question_formset.forms %}
        {{ question_form }}

        {% if question_form.nested %}
          {{ question_form.nested.management_form }}
          {{ question_form.nested.non_form_errors }}
          <div id='myForm2'>
          {% for choice_form in question_form.nested.forms %}
            {{ choice_form }}
          {% endfor %}
          </div>
        {% endif %}
      {% endfor %}
    </table>

    <button type="save">Save</button>
  </form>
</div>
<script src="{% static "surveys/dist/js/jquery.js" %}"></script>
<script src="{% static "surveys/dist/js/jquery.formset.js" %}"></script>
<script type="text/javascript">
  $(function(){
    $('#myForm1').formset({
      prefix: '{{ question_formset.prefix }}',
      formCssClass: 'dynamic-question_formset',
      addText: 'add question'
    });
    $('#myForm2').formset({
      prefix: '{{ choice_form.prefix }}',
      formCssClass: 'dynamic-choice_form',
      addText: 'add choice'
    });
  })
</script>
{% endblock %}

我最终使用了 this plugin!它有嵌套表单集示例的解释。