Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django formset : Save multiple forms from formset

I spent several days in order to add dynamically forms to formset and I find a way to do that. But I have a little issue with forms saving because it just saves the first form and not all forms from formset.

This is my formset :

DocumentFormSets = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1, max_num=4)

This is my template :

<fieldset>
    <legend class="title"><span class="name">{% trans 'Document form' %}</span></legend>
    {{ DocumentFormSet.management_form }}
    <div id="form_set">
      {% for form in DocumentFormSet.forms %}
        <div class='formset-document'>
          <table class='no_error'>
            <div class="row">
              <div class="col-xs-3">
                {{ form.title|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.language|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.format|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ form.upload|as_crispy_field }}
              </div>
            </div>
          </table>
        </div>
      {% endfor %}
    </div>
    <br>
    <input type="button" class="btn btn-default" value="Add More" id="add_more">
    <div id="empty_form" style="display:none">
      <table class='no_error'>
        <div class="row">
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.title|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.language|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.format|as_crispy_field }}
          </div>
          <div class="col-xs-3">
            {{ DocumentFormSet.empty_form.upload|as_crispy_field }}
          </div>
        </div>
      </table>
    </div>
</fieldset>

This is my JS part :

$('#add_more').click(function () {
  var form_idx = $('#id_form-TOTAL_FORMS').val();
  $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
  $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});

And this is my views.py file :

class PublicationCreateView(EdqmCreateView):
    """ Create publication with document form through formset """
    model = Publication
    template_name = 'freepub/publication/publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        context['DocumentFormSets'] = DocumentFormSets(self.request.POST or None, self.request.FILES or None)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formsets = context['DocumentFormSets']
        if form.is_valid() and formsets.is_valid():
            self.object = form.save()
            formsets.instance = self.object
            formsets.save()
        return super(PublicationCreateView, self).form_valid(form)

But with this function, it saves only the first document form in my formset :

I looked over id document form field and I get this :

enter image description here

The first title field get id_documents-0-title but when I add more forms, title field get always id_documents-undefined-title

How I can save my document forms from formsets ?

Thank you !

EDIT :

This is an edit from @HaiLang question :

This is my self.request.POST :

<QueryDict: {'csrfmiddlewaretoken': ['0LHaaEG1dkyZmOnP3X7037tZI45QrQOIRrQQAMhiOoTyeohDwQdcdTt08yuqH86Z'], 'category': ['23'], 'pub_id': ['PUBSDDD-55'], 'title': ['TESTPUBLIE'], 'description': [''], 'doc-TOTAL_FORMS': ['1'], 'doc-INITIAL_FORMS': ['0'], 'doc-MIN_NUM_FORMS': ['0'], 'doc-MAX_NUM_FORMS': ['4'], 'doc-0-title': ['doc1'], 'doc-0-language': ['FR'], 'doc-0-format': ['pdf'], 'doc-undefined-title': ['doc2'], 'doc-undefined-language': ['FR'], 'doc-undefined-format': ['pdf'], 'doc-__prefix__-title': [''], 'doc-__prefix__-language': [''], 'doc-__prefix__-format': [''], 'doc-__prefix__-upload': ['']}>

And this is my console.log :

Element kt.fn.init {}
like image 615
Essex Avatar asked Jul 16 '26 05:07

Essex


1 Answers

Luckily I just worked with FormSet recently so I can see the issue with the code in question.

(Edited by Ducky. Thank you!)

You have to set the same prefix between your views.py file and your app.js file. Because in your view file you are using prefix='doc' and in your javascript function you used form prefix.

So in your JQuery file you have to write :

(function ($) {
$('#add_more').click(function () {
    var form_idx = $('#id_doc-TOTAL_FORMS').val();
    // For debugging the issue
    // console.log('Element', $('#id_doc-TOTAL_FORMS'), 'Num of forms', form_idx);
    $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
    $('#id_doc-TOTAL_FORMS').val(parseInt(form_idx) + 1);
    console.log('Element', $('#id_doc-TOTAL_FORMS'));
});
})(jQuery)

You can overwrite your view like this :

class PublicationCreateView(CreateView):
    """ Create publication with document form through formset """
    model = Publication
    template_name = 'publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        document_queryset = Document.objects.all()
        context['DocumentFormSets'] = DocumentFormSet(self.request.POST or None, self.request.FILES or None, prefix='doc', queryset=document_queryset)
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        formsets = context['DocumentFormSets']
        // For debugging
        // print(self.request.POST)
        if form.is_valid() and formsets.is_valid():
            self.object = form.save()
            formsets.instance = self.object
            formsets.save()
        return super(PublicationCreateView, self).form_valid(form)
like image 186
Hai Lang Avatar answered Jul 18 '26 21:07

Hai Lang



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!