2012-12-02 10 views
13

Quando inserisco il mio formset, ottengo un errore MultiValueDictKeyError. In particolare:Come eseguire il debug di un Django MultiValueDictKeyError su Formset POST

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

La parte fondamentale è che il Django è alla ricerca per la chiave documents-0-attachment_ptr nei dati post. Ciò è fonte di confusione: un documento è una sottoclasse di un allegato. Tutti gli altri dati del post sono come previsto. Perché Django ha bisogno dei dati del puntatore nel mio formset?

Qui è la forma utilizzata nel 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 

E qui è il modello di documento:

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

Ulteriori informazioni:

Curiosamente, il post inital del formset funziona bene. È solo sui post di aggiornamento - quando ci sono moduli iniziali nel formset - quando ottengo questo errore. Succede anche quando provo a cancellare i moduli dal formset.

Inoltre, il formset è un formset in linea generico che utilizza forme django croccanti.

Aggiornamento

C'era una richiesta per il codice del modello utilizzato. Ecco la versione semplificata:

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

cosa è NoDirectoryClearableFileInput? Forse dovresti pubblicare il template html e il codice javascript ... – danihp

+0

NoDirectoryClearableFileInput è solo una sottoclasse del widget ClearableFileInput che visualizza solo il nome del file, non il percorso completo del file associato. – Erik

+0

Non è coinvolto JavaScript. – Erik

risposta

1

ho smesso questo errore aggiungendo attachment_ptr per l'elenco dei campi della mia forma. Così DocumentInlineForm è ora:

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 

Forse è qualcosa che non sapeva prima, ma fa Django richiede di fornire un puntatore alla superclasse in tutte le forme che utilizzano un modello di sottoclasse? Questo mi sorprende.

Mi piacerebbe scoprire perché questo campo del puntatore è richiesto, quindi ho aperto una domanda per dirlo qui: Why does my django formset need a pointer field reference?.

43

Questo non è il caso con OP, ma si incontrerà un MultiValueDictKeyError, se alcuni dei campi nascosti sono mancanti nel modello. Può accadere quando invece di quick e dirty {{form}}, i campi sono elencati nel modello uno per uno: {{form.field1}}, {{form.field2}}, lasciando esclusi i campi nascosti richiesti.

Per includere di nuovo fare qualcosa lungo le linee (per ogni modulo/forma in formset):

{% for hidden in form.hidden_fields %} 
    {{ hidden }} 
{% endfor %} 

o

{% for form in formset %}  
    {% for hidden in form.hidden_fields %} 
     {{ hidden }} 
    {% endfor %}  
{% endfor %} 
4

Io uso anche

{% for hidden in form.hidden_fields %} 
    {{ hidden }} 
{% endfor %} 

come questo uno

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

e risolvo il MultiValueDictKeyError

0

Questa non è la risposta al PO ma ho ottenuto lo stesso errore. Ho rimosso per errore {{ subform.id }} dal mio modello perché non potevo visualizzarlo visivamente e stavo riordinando il vecchio codice. nel codice HTML si otterrà qualcosa di simile a:

<input name="note_set-0-id" value="34632" id="id_note_set-0-id" type="hidden"> 
Problemi correlati