Em formação:
Eu gostaria de criar formulários aninhados como é melhor descrito por meio do exemplo fornecido em:
http://yergler.net/blog/2009/09/27/nested-formsets-with-django/
O tutorial nesta página parece ser muito bom e está tentando resolver o problema exato que estou encontrando.
Parece haver um problema com essa implementação no arquivo views.py quando não há dados de solicitação POST (ou seja, estamos realizando o preenchimento inicial do banco de dados).
O código pode ser visto na URL fornecida acima (se necessário, posso postar parte do código, mas temo que isso vá prejudicar as informações fornecidas aqui).
Aqui está o código views.py que está falhando (em negrito):
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
A mensagem de erro que estou recebendo é:
ValidationError at "urlName":
[u"ManagementForm data is missing or has been tampered with"]
Eu cavei mais fundo e parece que essa falha está ocorrendo na linha site-packages / django / forms / formsets.py
o is_valid()
a verificação está falhando porque alguns dos dados necessários do formulário de gerenciamento (form-TOTAL_FORMS, form-INITIAL_FORMS e form-MAX_NUM_FORMS) são inválidos. Aqui está a saída real de self.errors abaixo:
{u"TOTAL_FORMS": [u"This field is required."], u"INITIAL_FORMS": [u"This field is required."]}
Código:
edit_building.html:
{{buildings.management_form}}
{% para construção em edifícios.formas%}
{{ 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)
Notas:
Já examinei a documentação do django em https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform e não encontrei nada muito útil que discuta como esses valores são preenchidos automaticamente pelo DJANGO
Estou usando Django V1.5
Questões:
No caso de não haver dados POST e oo formulário está sendo gerado exclusivamente a partir do banco de dados, como os dados "form-TOTAL_FORMS" && "form-INITIAL_FORMS" devem ser preenchidos corretamente para solucionar esta falha?
Respostas:
4 para resposta № 1Atualizar:
Depois de olhar através o exemplo você forneceu há um trecho que se lê assim em forms.py
no final de add_fields()
método:
# store the formset in the .nested property
form.nested = [
TenantFormset(data = self.data,
instance = instance,
prefix = "TENANTS_%s" % pk_value)
]
o data
argumento está causando problemas porque é inicialmente vazio e internamente o Django irá determinar se um formulário está ligado por uma condicional semelhante a esta:
self.is_bound = data is not None
# Example
>>> my_data = {}
>>> my_data is not None
True
E como você pode ver um dicionário vazio em Python não é nenhum, então seu TenantFormset
é tratado como um bound
formulário, embora não seja. Você pode corrigi-lo com algo como o seguinte:
# 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)
]
Você poderia postar a visão e o código do formulário, bem como o código do modelo para o seu formulário?
Meu palpite é que você não está usando o ‘management_form’ em seu modelo (que adiciona os campos “form-TOTAL_FORMS” e “form-INITIAL_FORMS” que estão faltando), ou seja,
<form method="post">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>