Zagorodniy Olexiy
Zagorodniy Olexiy

Reputation: 2212

Django formset u'ManagementForm data is missing or has been tampered with'

In my Django project i use 3 forms on one view. 2 of this forms is formsets. There is how looks like my forms:

class HotelForm(forms.Form):
        country = forms.CharField(label=(u'Select Country'))
        city = forms.CharField(label=(u'Select City'))
        hotel = forms.ChoiceField(label=(u'Hotel Stars'))
        from_date = forms.CharField(label=(u'Date from'))
        to_date = forms.CharField(label=(u'Date to'))
        rooms = forms.IntegerField(label=(u'Rooms'), min_value=1)
        food = forms.ChoiceField(label=(u'Food'),
                widget = forms.Select, choices = FOOD_CHOICES)

class TouristsForm(forms.Form):
        adult = forms.IntegerField(min_value=1, initial=1)
        children = forms.IntegerField(label=(min_value=0, initial=0, required=False)

class ChildrenAgeForm(forms.Form):
        children_age = forms.IntegerField(min_value=2, max_value=10, initial=2, required=False)

Depending on numbers of field rooms of HotelForm i add formset TouristsFormSet using js:

$('#id_booking_form-rooms').on('change', function(e){
   var n = $('#id_booking_form-rooms').val() || 0;
   var html = "";

   for (var i = 0; i < n; i++) {
      html += "<input id='id_tourists-TOTAL_FORMS' type='hidden' value='1' name='tourists-TOTAL_FORMS'>"
      + "<input id='id_tourists-INITIAL_FORMS' type='hidden' name='tourists-INITIAL_FORMS'>"
      + "<input id='id_tourists-MIN_NUM_FORMS' type='hidden' name='tourists-MIN_NUM_FORMS'>"
      + "<input id='id_tourists-MAX_NUM_FORMS' type='hidden' name='tourists-MAX_NUM_FORMS'>"
      + "<div>Quantity of people in the room " + (i + 1) + "</div>"
      + "<br/><label for='id_tourists-" + i + "-adult'>Adults quantity:</label>"
      + "<input id='id_tourists-" + i + "-adult' type='number' name='tourists-" + i + "-adult' value='0'/>"
      + "<label for='id_tourists-" + i + "-children'>Children quantity:</label>"
      + "<input id='id_tourists-" + i + "-children' type='number' name='tourists-" + i + "-children' class='children_age' value='0'/>"
      + "<div class='extrafieldWrapperChAge'></div>";
      }
      $(".extrafieldWrapper").html(html);
});

Depending on number of children of formset TouristsFormSet i add formset ChildrenAgeFormSet using js:

$(".extrafieldWrapper").on('change', '.children_age', function(e){
   var n = $(this).val() || 0;
   var html = "";
   for (var i = 0; i < n; i++) {
      html += "<input id='id_childrenage-TOTAL_FORMS' type='hidden' value='1' name='childrenage-TOTAL_FORMS'>"
      + "<input id='id_childrenage-INITIAL_FORMS' type='hidden' name='childrenage-INITIAL_FORMS'>"
      + "<input id='id_childrenage-MIN_NUM_FORMS' type='hidden' name='childrenage-MIN_NUM_FORMS'>"
      + "<input id='id_childrenage-MAX_NUM_FORMS' type='hidden' name='childrenage-MAX_NUM_FORMS'>"
      + "<br/><label for='id_childrenage-" + i + "-children_age'>Children Age "+(i+1)+"</label>"
      + "<input id='id_childrenage-" + i + "-children_age' type='number' value='0' name='childrenage-" + i + "children_age' />";
      }
$(this).next('.extrafieldWrapperChAge').html(html);
});

There is how looks like my html file:

<div class="large-6 columns">
   <div class="fieldWrapper">
     {% if booking_form.city.errors %}
       <ol style="list-style-type:square" >
         {% for error in booking_form.city.errors %}
           <li><strong>This field is required</strong></li>
         {% endfor %}
        </ol>
      {% endif %}
      {{ booking_form.city.label_tag }}
      {{ booking_form.city }}
     </div>
 </div>
 <!-- and other HotelForm fields -->
 <div class="extrafieldWrapper">
 <!-- here is load formset fields -->
 </div>
 <div class="row">
   <input type="submit" value="Find">
 </div>

and there is looks like my view:

def post(self, request, *args, **kwargs):
  TouristsFormSet = formset_factory(TouristsForm, extra = 1, max_num = 15)
  ChildrenAgeFormSet = formset_factory(ChildrenAgeForm, extra = 1, max_num = 20)
  booking_form = HotelForm(request.POST, prefix='booking_form')
  tourists_formset = TouristsFormSet(request.POST, prefix='tourists')
  childrenage_formset = ChildrenAgeFormSet(request.POST, prefix='childrenage')
  if booking_form.is_valid() and tourists_formset.is_valid() and childrenage_formset.is_valid():
    ...

Everything work fine, but if i leave adult, children fields of TouristsFormSet and/or children age fields of ChildrenAgeFormSet with default value, i receive error ValidationError at /booking/, [u'ManagementForm data is missing or has been tampered with'].

I tried to compare html code in browser when i use js and without js just using {{tourists_formset}} and {{childrenage_formset}}. And its seems to me that its the same . When i use formsets without js everything works fine

Also in traceback i find this line return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max) when value of field children is 0 and _('ManagementForm data is missing or has been tampered with'), code='missing_management_form',

I will be thankful if somebody will help me with it.

Upvotes: 0

Views: 1273

Answers (1)

Alasdair
Alasdair

Reputation: 308799

The management form should be added once for each formset. In your JavaScript, it looks as if you are adding it once for each form.

Upvotes: 1

Related Questions