本文介绍了如何在Formset POST上调试Django MultiValueDictKeyError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我发布我的表单时,我得到一个MultiValueDictKeyError。具体来说:

  / core / customers / 1 / update / documents / 
中的MultiValueDictKeyErrorKey u'documents-0 -attachment_ptr在< QueryDict:{u'documents-1-last_modified_date'中找不到:'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],文件0注释':[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'NCQ15jA 7erX5dAbx20Scr3gWxgaTn3Iq'],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

这里是文档模型:

 
处理文档模型定义

from django.db import models
from ee e_core.models.attachments import从django.db.models.signals导入附件
从datetime导入pre_save
从django.utils.timezone导入utc

类从datetime导入datetime
文件(附件):

文档是附加元数据的附件。

creation_date = models.DateTimeField(
blank = True,
null = True,

document_type = models.CharField(
blank = True,
choices =(
('CONTRACT','Contract'),
('INVOICE','发票'),
('FACILITY' '设施变更表'),
('LOA','授权书'),
('USAGE','使用历史文件'),
('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

设置模型的元字段。

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
如果不是isinstance(实例,文档):
返回

如果不是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')

附加信息:



奇怪的是,formset的初始化功能正常,只有在更新的帖子 - 当formset中有初始表单时 - 当我收到此错误时,当我尝试从表单集中删除表单时也会发生。



另外, formset是使用django脆性表单的通用内联表单集。



更新



是使用模板代码的请求。以下是简化版本:

  {%load crispy_forms_tags%} 
{%从未来添加网址%}
< form action =method =postenctype =multipart / form-data>
{{formset.management_form}}
{%formform.forms%中的子表单}
{{subform.id}}
{%crispy子窗体%}
{%endfor%}
< div class =btn-toolbar>
< input class ='btn btn-primary'type =submitname =submitvalue =提交更改/>
< / div>
< / form>


解决方案

我通过添加 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 formset需要一个指针字段引用? / p>

When I post my formset, I get a MultiValueDictKeyError. Specifically:

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']}>"

The key part is that Django is looking for the key documents-0-attachment_ptr in the post data. This is confusing -- a Document is a subclass of an Attachment. All of the other post data is as expected. Why is Django needing pointer data in my formset?

Here is the form used in the formset:

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

And here is the Document model:

"""
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')

Additional info:

Curiously, the inital post of the formset works fine. It is only on update posts -- when there are initial forms in the formset -- when I get this error. It also happens when I try to delete forms from the formset.

Also, the formset is a generic inline formset using django crispy forms.

Update

There was a request for the template code used. Here is the simplified version:

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

I stopped this error by adding attachment_ptr to the field list of my form. So DocumentInlineForm is now:

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

Maybe it is something I didn't know before, but does Django require you to provide a pointer to the superclass in all forms that use a subclassed model? This surprises me.

I'd like to find out why this pointer field is required, so I've opened a question to address that here: Why does my django formset need a pointer field reference?.

这篇关于如何在Formset POST上调试Django MultiValueDictKeyError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-02 03:10