Django Management Form is failing because 'form-TOTAL_FORMS' and 'form-INITIAL_FORMS' aren't correctly populated

谁说我不能喝 提交于 2019-12-05 05:03:06

问题


Information:

I would like to create nested forms as is best described through the example provided at:

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

The tutorial at this page seems to be pretty good && it is attempting to accomplish the exact problem I am encountering.

There seems to be an issue with this implementation in the views.py file when there is no POST request data (I.e. we are performing the initial population from database).

The code can be seen at the URL provided above (if needed I can post some of the code, but I fear it will take away from the information provided here).

Here is the views.py code that is failing (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 am getting is:

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

I have dug deeper and it appears this failure is ocurring at line site-packages/django/forms/formsets.py

The is_valid() check is failing because some of the managementform required data (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.forms %}

 {{ 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:

  • I have already looked into the django documentation at https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform and did not find anything too useful that discusses how these values are automatically populated by DJANGO

  • I am using Django V1.5

Questions:

In the event that there is no POST data and the form is being generated solely from the database, how should the 'form-TOTAL_FORMS' && 'form-INITIAL_FORMS' data be correctly filled in to solve this failure?


回答1:


Update:

After looking through the example you provided there's a snippet that reads like this in forms.py at the end of the add_fields() method:

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

The data argument is causing problems because it's initially empty and internally Django will determine whether or not a form is bound by a conditional that's similar to this:

self.is_bound = data is not None

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

And as you can see an empty dictionary in Python isn't None, so your TenantFormset is treated as a bound form even though it isn't. You could fix it with something like the following:

# 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 post the view and form code as well as the template code for your form?

My guess is that you're not using the ‘management_form’ in your template (which adds the “form-TOTAL_FORMS” and “form-INITIAL_FORMS” fields that you're missing), i.e.

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


来源:https://stackoverflow.com/questions/17518018/django-management-form-is-failing-because-form-total-forms-and-form-initial-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!