Как отлаживать Django MultiValueDictKeyError на Formset POST
Когда я отправляю свой набор форм, я получаю MultiValueDictKeyError. В частности:
MultiValueDictKeyError at /core/customers/1/update/documents/
"Key u'documents-0-attachment_ptr' not found in <QueryDict: {u'documents-1-last_modified_date': [u''], u'documents-1-name': [u''], u'documents-MAX_NUM_FORMS': [u''], u'documents-0-attachment_file': [u''], u'documents-INITIAL_FORMS': [u'1'], u'documents-1-document_type': [u''], u'documents-0-notes': [u''], u'documents-1-notes': [u''], u'submit': [u'Submit changes'], u'documents-0-DELETE': [u'on'], u'documents-1-attachment_file': [u''], u'documents-0-document_type': [u''], u'documents-TOTAL_FORMS': [u'2'], u'documents-0-name': [u'test'], u'documents-1-creation_date': [u''], u'documents-0-creation_date': [u'2012-12-01 23:41:48'], u'csrfmiddlewaretoken': [u'NCQ15jA7erX5dAbx20Scr3gWxgaTn3Iq', u'NCQ15jA7erX5dAbx20Scr3gWxgaTn3Iq', u'NCQ15jA7erX5dAbx20Scr3gWxgaTn3Iq'], u'documents-0-last_modified_date': [u'2012-12-01 23:41:48']}>"
Ключевой частью является то, что Django ищет ключ documents-0-attachment_ptr
в данных сообщения. Это сбивает с толку - Документ является подклассом Приложения. Все остальные данные будут такими, как ожидалось. Почему Django нуждается в данных указателя в моем наборе форм?
Вот форма, используемая в наборе форм:
class DocumentInlineForm(forms.ModelForm): # pylint: disable=R0924
attachment_file = forms.FileField(widget=NoDirectoryClearableFileInput)
notes = forms.CharField(
required=False,
widget=forms.Textarea(attrs={'rows': 2,}),
)
helper = DocumentInlineFormHelper()
class Meta: # pylint: disable=W0232,R0903
fields = (
'attachment_file',
'creation_date',
'document_type',
'last_modified_date',
'name',
'notes',
)
model = Document
И вот модель документа:
"""
Handles document model definitions.
"""
from django.db import models
from eee_core.models.attachments import Attachment
from django.db.models.signals import pre_save
from datetime import datetime
from django.utils.timezone import utc
class Document(Attachment):
"""
A document is an attachment with additional meta data.
"""
creation_date = models.DateTimeField(
blank=True,
null=True,
)
document_type = models.CharField(
blank=True,
choices=(
('CONTRACT', 'Contract'),
('INVOICE', 'Invoice'),
('FACILITY', 'Facility change form'),
('LOA', 'Letter of authorization'),
('USAGE', 'Usage history document'),
('OTHER', 'Other'),
),
default=None,
null=True,
max_length=8,
)
last_modified_date = models.DateTimeField(
blank=True,
null=True,
)
notes = models.TextField(
blank=True,
null=True,
)
class Meta(Attachment.Meta): # pylint: disable=W0232,R0903
"""
Sets meta fields for model.
"""
app_label = 'core'
def __str__(self):
return unicode(self).encode('utf-8')
def __unicode__(self):
return unicode(self.name)
def pre_save_callback(sender, instance, *args, **kwargs): # pylint: disable=W0613
if not isinstance(instance, Document):
return
if not instance.creation_date:
instance.creation_date = datetime.utcnow().replace(tzinfo=utc)
instance.last_modified_date = datetime.utcnow().replace(tzinfo=utc)
pre_save.connect(pre_save_callback, dispatch_uid='document_pre_save')
Дополнительная информация:
Любопытно, что исходный пост набора форм отлично работает. Это только на сообщениях с обновлением - когда в formet есть исходные формы - когда я получаю эту ошибку. Это также происходит, когда я пытаюсь удалить формы из набора форм.
Кроме того, formet является типичным встроенным набором форм, использующим чистые формы django.
Обновление
Был запрошен код используемого шаблона. Вот упрощенная версия:
{% load crispy_forms_tags %}
{% load url from future %}
<form action="" method="post" enctype="multipart/form-data">
{{ formset.management_form }}
{% for subform in formset.forms %}
{{ subform.id }}
{% crispy subform %}
{% endfor %}
<div class="btn-toolbar">
<input class='btn btn-primary' type="submit" name="submit" value="Submit changes" />
</div>
</form>
Ответы
Ответ 1
Я остановил эту ошибку, добавив attachment_ptr
в список полей моей формы. Итак, DocumentInlineForm
теперь:
class DocumentInlineForm(forms.ModelForm): # pylint: disable=R0924
attachment_file = forms.FileField(widget=NoDirectoryClearableFileInput)
notes = forms.CharField(
required=False,
widget=forms.Textarea(attrs={'rows': 2,}),
)
helper = DocumentInlineFormHelper()
class Meta: # pylint: disable=W0232,R0903
fields = (
'attachment_ptr',
'attachment_file',
'creation_date',
'document_type',
'last_modified_date',
'name',
'notes',
)
model = Document
Возможно, это то, чего я раньше не знал, но требует ли Django указатель на суперкласс во всех формах, использующих подклассу? Это меня удивляет.
Я хотел бы узнать, почему это поле указателя требуется, поэтому я открыл вопрос, чтобы обратиться к этому здесь: Почему для моего набора форм django требуется ссылка на поле указателя?.
Ответ 2
Это не относится к OP, но вы встретите MultiValueDictKeyError
, если некоторые скрытые поля отсутствуют в шаблоне. Это может произойти, когда вместо быстрого и грязного {{form}}
поля поочередно перечисляются в шаблоне: {{form.field1}}
, {{form.field2}}
, оставляя необходимые скрытые поля.
Чтобы включить их обратно, сделайте что-нибудь вдоль строк (для каждой формы/формы в наборе форм):
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
или
{% for form in formset %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endfor %}
Ответ 3
Я также использую
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
как этот
<div role="tabpanel" class="tab-pane active" id="email">
{% csrf_token %}
{{ eformset.management_form}}
<div class="panel panel-default">
<div class="panel-body">
<div id="addemail" class="btn btn-success">
<span class="glyphicon glyphicon-plus" >
</span>
</div>
<p><br></p>
{% for f in eformset %}
{% for hidden in f.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="item_email_set">
<table class="table table-condensed table-bordered">
<tr>
{% for field in f.visible_fields %} <!---->
<td>
{{ field.label }}
</td>
{% endfor %}
<td>
</td>
</tr>
<tr>
{% for field in f.visible_fields %}
<td>
{{field.errors.as_ul}}
{{field}}
</td>
{% endfor %}
<td class="btncolumn">
<p style="">
<a class="delete_email_set" href="#">
<div class="btn btn-danger">
<span class="glyphicon glyphicon-remove" >
</span>
</div>
</a>
</p>
</td>
</tr>
</table>
</div>
{% endfor %}
</div>
</div>
</div>
и я разрешаю MultiValueDictKeyError