Django form control not working because "form-TOTAL_FORMS" and "form-INITIAL_FORMS" are not filled out correctly

Information:

I would like to create nested forms as best described in the example provided in:

http://yergler.net/blog/2009/09/27/nested-formsets-with-django/

The tutorial on this page seems to be pretty good && it tries to accomplish the exact problem I'm running into.

There seems to be a problem with this implementation in the views.py file when there is no POST request data (Ie we are executing the initial aggregate from the database).

The code can be seen at the above URL (I can post some of the code if necessary, but I'm afraid it will take away the information provided here).

Here is the Views.py code that fails (in bold):

block = get_object_or_404(models.Block, id=block_id)

if request.method == 'POST':
    formset = forms.BuildingFormset(request.POST, instance=block)

    if formset.is_valid():
        rooms = formset.save_all()

        return redirect('block_view', block_id=block.id)

else:
    formset = forms.BuildingFormset(instance=block)  #This is the line that is throwing the ValidationError 

      

The error message I'm getting is:

ValidationError at "urlName":
[u'ManagementForm data is missing or has been tampered with']

      

I dug deeper and it seems that this crash is happening at site-packages / django / forms / formsets.py line

Validation is_valid()

does not work because some of the data required for the control form (form-TOTAL_FORMS, form-INITIAL_FORMS, and form-MAX_NUM_FORMS) is invalid. Here is the actual output of self.errors below:

{u'TOTAL_FORMS': [u'This field is required.'], u'INITIAL_FORMS': [u'This field is required.']}

      

code:

edit_building.html:

{{buildings.management_form}}

{% for building in buildings.%}

 {{ building }}

 {% if building.nested %}   
   {% for formset in building.nested %}   
     {{ formset.as_table }}   
   {% endfor %}   
 {% endif %}

      

{% endfor%}

views.py:

def should_delete(self, form):
    """Convenience method for determining if the form’s object will
    be deleted; cribbed from BaseModelFormSet.save_existing_objects."""

    if self.can_delete:
        raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
        should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
        return should_delete

    return False

def save_all(self, commit=True):
    """Save all formsets and along with their nested formsets."""

    # Save without committing (so self.saved_forms is populated)
    # — We need self.saved_forms so we can go back and access
    #    the nested formsets
    objects = self.save(commit=False)

    # Save each instance if commit=True
    if commit:
        for o in objects:
            o.save()

    # save many to many fields if needed
    if not commit:
        self.save_m2m()

    # save the nested formsets
    for form in set(self.initial_forms + self.saved_forms):
        if self.should_delete(form): continue

        for nested in form.nested:
            nested.save(commit=commit)

      

forms.py:

def should_delete(self, form):
    """Convenience method for determining if the form’s object will
    be deleted; cribbed from BaseModelFormSet.save_existing_objects."""

    if self.can_delete:
        raw_delete_value = form._raw_value(DELETION_FIELD_NAME)
        should_delete = form.fields[DELETION_FIELD_NAME].clean(raw_delete_value)
        return should_delete

    return False

def save_all(self, commit=True):
    """Save all formsets and along with their nested formsets."""

    # Save without committing (so self.saved_forms is populated)
    # — We need self.saved_forms so we can go back and access
    #    the nested formsets
    objects = self.save(commit=False)

    # Save each instance if commit=True
    if commit:
        for o in objects:
            o.save()

    # save many to many fields if needed
    if not commit:
        self.save_m2m()

    # save the nested formsets
    for form in set(self.initial_forms + self.saved_forms):
        if self.should_delete(form): continue

        for nested in form.nested:
            nested.save(commit=commit)

      

Notes:

Questions:

In the absence of POST data and the form is generated exclusively from the database, how should the "form-TOTAL_FORMS" && 'form-INITIAL_FORMS' be filled in correctly to solve this problem?

+2


source to share


1 answer


Update:

Looking through the example , you provided a snippet there that reads like this at forms.py

the end of the method add_fields()

:

# store the formset in the .nested property
form.nested = [
    TenantFormset(data = self.data,
                  instance = instance,
                  prefix = 'TENANTS_%s' % pk_value)
]

      

The argument data

causes problems because it is initially empty, and internally Django determines if the form is bound to a condition, which is similar to this:

self.is_bound = data is not None

# Example
>>> my_data = {}
>>> my_data is not None
True

      

And since you can see that an empty dictionary in Python is not None, yours is TenantFormset

treated as a form bound

even if it is not. You can fix it like this:



# store the formset in the .nested property
form.nested = [
    TenantFormset(data = self.data if any(self.data) else None,
                  instance = instance,
                  prefix = 'TENANTS_%s' % pk_value)
]

      


Could you please post the view and form code and template code for your form?

I am assuming you are not using "control_form" in your template (which adds the "TOTAL_FORMS" and "form-INITIAL_FORMS" form fields you are missing), i.e.

<form method="post">
    {{ formset.management_form }}
    <table>
        {% for form in formset %}
        {{ form }}
        {% endfor %}
    </table>
</form>

      

+4


source







All Articles