问题
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