4

So I have set up the following codes for sample from followed by inline formset of its foreign key, sample detail. I also added some dynamic feature to it so that you could add more rows for the formset via Jquery. I got the Jquery section from http://stackoverflow.com/questions/501719/dynamically-adding-a-form-to-a-django-formset-with-ajax. I tried both implementation but it appears to have the same result. I am wondering if I did something wrong in the view.

views.py

def project_detail (request, project_id):
     project = Project.objects.get(id = project_id)
     sample_form = SampleForm(request.POST or None, request.FILES or None, instance = project)
     SampleInlineFormSet = inlineformset_factory(Sample, SampleDetail, form=SampleDetailForm, extra=1, can_delete = False)
     formset = SampleInlineFormSet(request.POST or None, request.FILES or None, prefix="nested")
     if request.method == "POST":

        if 'sampleform' in request.POST:
            if sample_form.is_valid() and formset.is_valid():
                 sample_temp = sample_form.save()
                 sample = Sample.objects.get(pk = sample_temp.pk)
                 objects = formset.save(commit=False)
                 for object in objects:
                       object.sample = sample
                       object.save()

                 messages.success(request, "Sucessfully Created New Sample Log" )
                 return HttpResponseRedirect(reverse('projstatus:project_detail', args=(project_id,)))           
     context = {'project' : project, "sample_form":sample_form, 'formset' : formset}
     return render(request, 'projstatus/detail.html', context)   

forms.py

<form method='POST' action='' enctype='multipart/form-data'>{% csrf_token %}
             {% crispy sample_form %}

             <div id="form_set">
                 {{ formset.management_form }}
                 {% for form in formset.forms %}
                     <table class='no_error'>

                         {{ form.as_table }}
                     </table>
                 {% endfor %}
             </div>
             <input type="button" value="Add More" id="add_more">

             <div id="empty_form" style="display:none">
                 <table class='no_error'>
                     {{ formset.empty_form.as_table }}

                 </table>
             </div>
             <script>
                 $('#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);
                 });
             </script>


              <button type='submit' class='save btn btn-default' name = 'sampleform'>Save</button>      

             </form>

However, I have this problem that only the first formset instance is ever saved. no matter how many I put in dynamically. Could someone please help me?

Edit:

The look of the form enter image description here

POST data when using Jquery to add one more instance (2 instances in total) enter image description here

POST data when not using Jquery, setting extra = 2. (2 instances in total) enter image description here

mrehan
  • 1,122
  • 9
  • 18
Hansong Li
  • 417
  • 2
  • 11
  • 26
  • 1
    The problem could be in your `#add_more` click handler. Compare the values of `request.POST` with and without Javascript (adjust `extra` in the view instead of clicking 'add more'), and make sure you are submitting the exact same data. – Alasdair Nov 21 '16 at 17:46
  • 1
    @Alasdair Hi thanks for the comments. I updated with POST data. Seems that it might be the "undefined" thing in Jquery case that is causing the problem – Hansong Li Nov 21 '16 at 21:03
  • Your jQuery post data is missing `nested-1-id`, `nested-1-location` and so on. – Alasdair Nov 21 '16 at 21:51
  • @Alasdair Thanks! I still failed to see which part did I make mistake.... Anyway thanks so much – Hansong Li Nov 22 '16 at 19:42
  • You may want to draw inspiration from how `django.contrib.admin` handles dynamically adding inline formset forms in [inlines.js](https://github.com/django/django/blob/b63d0c54b05ede2589e2b720eb0c102c02891962/django/contrib/admin/static/admin/js/inlines.js). – tutuDajuju Nov 23 '16 at 14:29

2 Answers2

3

I think your issue is with your javascript. It seems you took that snippet from another example that's floating around.

var form_idx = $('#id_form-TOTAL_FORMS').val();

For this to work, there needs to be an element with id of id_form-TOTAL_FORMS.

But I think your form will probably have this input with an id of something like id_nested-TOTAL_FORMS or something similar. As a result, I don't think your javascript is actually updating the Formset's management form data.

You should inspect your html on the page and see what the id of this input is. Also, use the javascript console to see what your JS code is really doing.

Esteban
  • 2,444
  • 2
  • 19
  • 19
1

As with the previous answer, the nested-TOTAL_FORMS field value needs updating with the number of rows each time you add one. You're currently updating a field form-TOTAL_FORMS which doesn't exist.

Try updating the js from #id_form-TOTAL_FORMS to #id_nested-TOTAL_FORMS

There may also be a way to get the field ID as a template variable but that escapes me at the moment.

Andee
  • 753
  • 3
  • 12