1

I am creating a web app to dynamically add forms using jQuery and process them with a django backend. I've used formsets in django as per the documentation at https://docs.djangoproject.com/en/dev/topics/forms/formsets/ and trying to follow the example at http://stellarchariot.com/blog/2011/02/dynamically-add-form-to-formset-using-javascript-and-django/ and at stackoverflow at Dynamically adding a form to a Django formset with Ajax.

The problem I am having is that when I submit the form I do not get any POST data. When I remove the variable {{ formset.management_form}} I get data to POST but get the error [u'ManagementForm data is missing or has been tampered with']. If I put the management form in the template(which I should) I get no POST data. Anyone know the solution for this?

forms.py
from django import forms
from busker.models import *
from django.forms import ModelForm



class UploadFileForm(ModelForm):
   class Meta:
      model = UploadFile

class Category(models.Model):
    category = models.CharField(max_length = 50)


    def __unicode__(self):
        return self.name

models.py

from django.db import models

class UploadFile(models.Model):
    title = models.CharField(max_length = 50)
    file  = models.FileField(upload_to = 'test')

    def __unicode__(self):
        return self.name

class CategoryForm(ModelForm):
   class Meta:
      model = Category

views.py

def submit(request,action=''):

    if request.user.is_authenticated():
        class RequiredFormSet(BaseFormSet):
            def __init__(self, *args, **kwargs):
                super(RequiredFormSet, self).__init__(*args, **kwargs)
                for form in self.forms:
                    form.empty_permitted = False
        UploadFileFormSet = formset_factory(UploadFileForm,extra=2, max_num=10, formset=RequiredFormSet)

        if request.method == 'POST':    
            uploadfile_formset = UploadFileFormSet(request.POST, request.FILES,prefix='songs')
            category_form= CategoryForm(request.POST,prefix = 'category')



            if uploadfile_formset.is_valid and category_form.is_valid:
                return HttpResponseRedirect('/') #going to the home root
            else:
                return HttpResponseRedirect('/contact') #testing to see if it fails
        else:
            uploadfile_formset = UploadFileFormSet(prefix = 'songs')
            category_form= CategoryForm(prefix = 'category') 

            t = loader.get_template('submit.html')
            c = RequestContext(request, {
                 'uploadfile_formset': uploadfile_formset,
                 'category_form': category_form,
                'head_title':  u'Submit Song',
                'page_title': 'Submit Song',
                })

            return HttpResponse(t.render(c))

templates (submit.html)

<form id="songform" name="songform" enctype="multipart/form-data" action="" method="POST">{% csrf_token %}
     {{uploadfile_formset.management_form}}
     <div id="songforminputs">
    {{category_form.as_p}}
     {% for formset in uploadfile_formset %}
         <div id="dynamicInput">
         <p class = "songSubmitForm" > Song {{forloop.counter}} </p>   
         {% for field in formset %}
             <label class="submitForm" for="title">{{ field.label }}</label>
             {{field|add_class:"submitForm" }}
              </br>
         {% endfor %}
         </div>
       {% endfor %}

       </div>

   <input type="button" value="Add another text input" onClick="addInput('dynamicInput');">
   <input type="button" value="Remove a text input" onClick="removeInput('dynamicInput');">
   <input type="submit" name="submitbutton" id="submitbutton" value="" >

</form>

jQuery / javascript portion

<script type="text/javascript">
var counter = 2;
var minimum = 2;
var limit = 5;

function addInput(divName){
     if (counter == limit)  {
          alert("You have reached the limit of adding " + counter + " inputs");
     }
     else {

          var newdiv = document.createElement('div');
          newdiv.id = "dynamicInput";
          newdiv.innerHTML = "<p class = 'songSubmitForm' > Song " + (counter+1) +"</p>"  + "<label for='title' class='submitForm' >Title</label>" + "<input id ='id_form-" + (counter)+ "-title'type='text' class='contact' name='form-" + counter +"-title'>" + "</br>" + "<label for='file' class='submitForm' >File</label>" + " <input id='id_form-"+counter+"-file' type='file' class='contact' name='form-"+counter+"-file'>" + "</br>" + "</br>";
          document.getElementById('songforminputs').appendChild(newdiv);
          counter++;
     }
}

function removeInput(divName){
     if (counter == minimum)  {
          alert("You need at least " + counter + " inputs");
     }
     else {
         $('div#dynamicInput:last-child').remove()
          counter--;
     }
}

</script>
Community
  • 1
  • 1
jeremy
  • 11
  • 1
  • 4
  • How do you know you're "not getting any POST data". Your action on POST is just 'pass'. What happens when you put real code there? – Daniel Roseman Jun 17 '12 at 18:01
  • So it turns out the problem was with the other piece of code that I removed from the original code. Basically I have two models/forms related to a view. When I assign request.POST to each model there is no POST data passed. When I remove one request.POST from the model I can get it to work. I am still stuck at the problem that I cannot get POST data on two models. – jeremy Jun 18 '12 at 01:00

1 Answers1

0

I don't think you said you were using django-crispy-forms, however, I'll post this here for anyone encountering this error that is, and who knows, maybe it will help you too.

I recently encountered a very similar problem when attempting to use multiple crispy inline formsets. I had added {{ formset.management_form }} before using {% cirspy formset.form formset.form.helper %}.

Face-palm

When I included the management forms, no data from the form would be available on post. When I didn't include the management forms, django complained with [u'ManagementForm data is missing or has been tampered with'].

To fix this just use crispy-forms the way it's designed: {% crispy formset formset.form.helper %}. That way there's no need to include the management form in it's own tag, which just seems to confuse Django.

Alex
  • 65
  • 1
  • 8