Django: Faltan datos de ManagementForm ... Formset no se valida. ¿Por qué?

Por alguna razón, mi conjunto de formularios no se validará después de que lo envíe. ¿Alguna idea sobre la forma en que esto puede estar sucediendo?

# modelos.py

class Department(models.Model):
  department = models.CharField(verbose_name = "Department Name", max_length=100)
  description = models.TextField(verbose_name = "Description", blank=True, null=True)
  sp_description = models.TextField(verbose_name = "Description (Spanish)", blank=True, null=True)
  phone = PhoneNumberField()
  phone_ext = models.CharField(max_length=10, blank=True)

  #Relations
  provider = models.ForeignKey(Provider, blank=True, null=True)
  services_offered = models.ManyToManyField(ServiceType)

  def __unicode__(self):
    return self.department

# view.py

def display_step5(request):
    msg = ''
    email = request.session.get('email')
    provider_obj = retrieve_provider_instance(email)
    AddDepartmentFormSet = inlineformset_factory(Provider, Department, extra=0)
    if is_authenticated(request):
        AddDepartmentFormSet = inlineformset_factory(Provider, Department, extra=0)
        if request.method=='POST':
            if 'add_department' in request.POST:
                cp = request.POST.copy()
                cp['department-TOTAL_FORMS'] = int(cp['department-TOTAL_FORMS'])+ 1
                new_department = AddDepartmentFormSet(cp, prefix='department', instance=provider_obj)
            elif 'submit' in request.POST:
                formset = AddDepartmentFormSet(request.POST, instance=provider_obj)
                instances = formset.save(commit=False)
                for instance in instances:
                    instance.provider = provider_obj
                    instance.save()
                return HttpResponse("Departments have been added")
        else:
            new_department = AddDepartmentFormSet(prefix='department', instance=provider_obj)

    else:
        return HttpResponseRedirect(reverse('health.register.views.display_auth'))
    return render_to_response('step5-test.html',
{'department': new_department}, context_instance=RequestContext(request))

step5-test.html

<form method='post' action='{{request.path}}'>{% csrf_token %}
  <fieldset>
    <legend>Departments</legend>
      {{ department.management_form }}
      {% for form in department.forms %}
        <HR> <div><table>{{form.as_table}}</table></div>
      {% endfor %}
     <BR/> 
     <input title='Add a new department' type='submit' name='add_department' value='Add-Another-Department' />
    </fieldset>
    <BR/><BR/>
    <input title='Submit this form' type='submit' name='submit' value='Submit' />
</form>

Seguimiento (solución):

Brant ofreció dar una idea de por qué estaba ocurriendo el error. En mi caso, su conocimiento me ayudó a construir un truco que funcionó mejor para mi situación. Este truco parece aplicable para conjuntos de formularios que pueden haber sido modificados de cierta manera dentro de la plantilla. En mi caso, mi conjunto de formularios se volvió complicado y requirió algo de ajax para hacerlo más fácil de usar.

El "retrieve_provider_instance (correo electrónico)" era una forma dinámica de recuperar el objeto proveedor basado en varios criterios establecidos en la base de datos (alrededor de 200 líneas de código vomit).

El siguiente truco funcionó para mí, después de una depuración extensa. Lo resolví agregando esto lo siguiente campo escondido en el bucle "for" de mi plantilla

{% {for form in formset.forms %}
                     <tr>
                      <td>
                         {% if form.instance.pk %} <!--- if instance already exists on db --->  
                         {{ form.DELETE }}
                         <input type='hidden' name="department_set-{{ forloop.counter0 }}-id" id="id_department_set-{{ forloop.counter0 }}-id"  value={{ form.instance.pk }} />
                         {% endif %}
                      Name: <br/> {{ form.department}} <br/>
                      Phone Number: <br/> {{ form.phone }} <br/>
                      Phone Ext: <br/> {{ form.phone_ext }}</td>
                      <td>Description: <br/> {{ form.description }}</td>
                      <td>Description (Spanish): <br/> {{ form.sp_description }}</td>
                      <td>Services Provided: <br/> {{ form.services_offered }}</td>
                      <td></td>
                   </tr>
                   {% endfor %} 

Acepté la respuesta de Mark porque era mucho más aplicable a la pregunta específica que estaba haciendo. Con suerte, esto ayudará a otros usuarios en el futuro que intenten implementar este ejemplo. De hecho, asignar el 'prefijo' al enviar es la forma correcta y tiene más sentido.

Gracias por todas vuestras respuestas.

Saludos cordiales Matt


Seguimiento: Creo que pude haber encontrado parte de mi problema. Pero aún no está resuelto.

Aquí hay información adicional que puede ayudar a resolver el problema. ¿Es posible que los datos POST incorrectos estén estropeando esto? Y si es así, ¿cómo puedo solucionar esto?

Esto es lo que sucede después de enviar el conjunto de formularios (en este caso, solo hay un formulario):

El rastreo es el siguiente:

Archivo "/home/mhjohnson/webapps/resourcedb/lib/python2.6/django/forms/formsets.py" en _management_form 68. raise ValidationError ('Los datos de ManagementForm faltan o han sido manipulados')

Estos son mis datos POST:

department-0-phone_ext -----> u'222'

department-0-id -----> u''

department-0-services_offered -----> u'2'

department-0-phone -----> u'222-222-2222'

department-INITIAL_FORMS -----> u'0'

submit -----> u'Submit'

department-MAX_NUM_FORMS -----> u''

department-0-department -----> u'Test 1'

department-0-provider -----> u''

department-TOTAL_FORMS -----> u'1'

csrfmiddlewaretoken -----> u'92a39322b16ed7e5e10dbd6c5ac64bf4'

department-0-description -----> u'Blah blah'

department-0-sp_description -----> u'....'

¿Alguna idea?

preguntado el 09 de enero de 11 a las 10:01

sangra correctamente el archivo views.py, no podemos leerlo.

¡Guau! Lo siento por eso. Había usado 'tabulación' en lugar de cuatro espacios para mis sangrías. Eso parece crear muchos problemas. ¿Puedes leerlo ahora? -

2 Respuestas

Tu problema está aquí:

       if request.method=='POST':
            if 'add_department' in request.POST:
                cp = request.POST.copy()
                cp['department-TOTAL_FORMS'] = int(cp['department-TOTAL_FORMS'])+ 1
                new_department = AddDepartmentFormSet(cp, prefix='department', instance=provider_obj)
            elif 'submit' in request.POST:
                formset = AddDepartmentFormSet(request.POST, instance=provider_obj)
                instances = formset.save(commit=False)
                for instance in instances:
                    instance.provider = provider_obj
                    instance.save()
                return HttpResponse("Departments have been added")
        else:
            new_department = AddDepartmentFormSet(prefix='department', instance=provider_obj)

Si no hay POST, pasa un prefijo de 'departamento'. Si 'add_department' está en el POST, pasa el prefijo de 'departamento'. Sin embargo, cuando 'enviar' está en el POST, no pasa el prefijo. Sin el prefijo, el conjunto de formularios no puede encontrar los datos adecuados en el POST.

Respondido el 11 de enero de 11 a las 16:01

Buena llamada, perdí eso por completo. +1 - Brant

Mark Lavin, esto hace que la solución sea mucho más simple. Descubrí por primera vez el método de Brant después de depurarlo durante varias horas. Publiqué mi trabajo en mi edición, usando su método. Pero tendré el tuyo en mente para el futuro. - Mate

Dos cosas me llaman la atención ...

Primero, no debería necesitar hacer esta parte:

for instance in instances:
   instance.provider = provider_obj
   instance.save()

Eso se soluciona cuando haces esto:

formset = AddDepartmentFormSet(request.POST, instance=provider_obj)

En segundo lugar, su código en la parte superior:

provider_obj = retrieve_provider_instance(email)

Puede que no esté funcionando. En el rastreo que proporcionó, no parece que el proveedor esté llegando allí ...

department-0-provider -----> u''

Respondido el 11 de enero de 11 a las 15:01

Brillante, Brant. Después de mucha frustración, descubrí el problema alrededor de las 5 de la mañana. Eres un tipo inteligente. Ojalá hubiera recibido tu consejo antes. Voy a señalar mi respuesta a continuación para resolver el problema. - Mate

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.