title: Django nested formsets adding forms dynamically
body: <p>I'm trying to create a survey page using Django that has the functionality to add questions and choices(for each question) dynamically. I have three following model classes: Survey, Question and Choice.</p>
  
  <p>I did a lot of research to figure out how to go about implementing the forms and it seems nested formsets using inline_formsets is the right way to go(<a href="https://micropyramid.com/blog/how-to-use-nested-formsets-in-django/" rel="nofollow noreferrer">I used this tutorial</a>). 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(<a href="https://github.com/elo80ka/django-dynamic-formset/blob/master/docs/usage.rst" rel="nofollow noreferrer">This library</a>) does not have an example for nested formsets and I'm not sure if it supports it.
  This code is what i have so far:</p>
  
  <p>forms.py</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>views.py</p>
  
  <pre><code>@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)
  </code></pre>
  
  <p>create.html</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>{% extends 'surveys/base.html' %}
  {% load static %}
  {% block container %}
  &lt;div class="container"&gt;
    &lt;h1&gt; Create New Survey &lt;/h1&gt;
    &lt;form method="post"&gt;
      {% csrf_token %}
      {{ question_formset.management_form }}
      {{ question_formset.non_form_errors }}
      {{ survey_form.as_p }}
      &lt;table id='myForm1'&gt;
        {% for question_form in question_formset.forms %}
          {{ question_form }}
  
          {% if question_form.nested %}
            {{ question_form.nested.management_form }}
            {{ question_form.nested.non_form_errors }}
            &lt;div id='myForm2'&gt;
            {% for choice_form in question_form.nested.forms %}
              {{ choice_form }}
            {% endfor %}
            &lt;/div&gt;
          {% endif %}
        {% endfor %}
      &lt;/table&gt;
  
      &lt;button type="save"&gt;Save&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
  &lt;script src="{% static "surveys/dist/js/jquery.js" %}"&gt;&lt;/script&gt;
  &lt;script src="{% static "surveys/dist/js/jquery.formset.js" %}"&gt;&lt;/script&gt;
  &lt;script type="text/javascript"&gt;
    $(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'
      });
    })
  &lt;/script&gt;
  {% endblock %}</code></pre>
  </div>
  </div>
  </p>