为什么我的django formset需要一个指针字段引用? [英] Why does my django formset need a pointer field reference?

查看:116
本文介绍了为什么我的django formset需要一个指针字段引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

没有什么比不理解为什么有效的东西更糟糕。几天前我问了这个问题,想出了一个修复,但是我不知道为什么这样做:



如何在Formset POST上调试Django MultiValueDictKeyError



为什么formset需要一个指针字段引用formset模型的超类?我有其他的formets就像这样不需要。



为了使这是一个独立的问题,这里是详细信息:



当我发布我的表单时,我得到一个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自然需要一种从一个到另一种的指针,否则它不可能知道父表中哪一行在孩子更改时更新。


Nothing is worse than not understanding why something works. I asked this question a couple of days ago and figured out a fix, but I don't know why it works:

How to debug a Django MultiValueDictKeyError on Formset POST.

Why does the formset need a pointer field reference to the superclass of the formset's model form model? I have other formsets just like this that don't.

To make this a standalone question, here are the details:

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.

解决方案

Don't forget that a subclass of a non-abstract model is really just a one-to-one relationship between the two models. So naturally Django needs some sort of pointer from one to the other, otherwise it can't possibly know which row in the parent table to update when the child changes.

这篇关于为什么我的django formset需要一个指针字段引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆