2012-07-31 37 views
10

Tengo un menú desplegable en un modelo y el usuario no debería poder cambiar el valor seleccionado. Encontré que un disabled hace exactamente lo que necesito. Sin embargo, hay una rareza en esto:Django: Disabled Dropdown no envía información de vuelta a POST

La primera vez que se abre el formulario (GET) se selecciona el valor y el usuario no puede cambiar el valor. que es grande:

enter image description here

Pero tan pronto como hay un error de validación con un unrelated field y la POST envía al usuario de vuelta a la misma forma, la información anterior se pierde. El menú desplegable deshabilitado de la clave externa ya no contiene ningún valor y es muy irritante.

enter image description here

hice algunas investigaciones y encontró algo en stackoverflow y parece cuando un widget ForeignKey-desplegable está desactivada, no se envían datos de vuelta en absoluto. Mientras que la validación puede ser anulada para no arrojar ningún error para el campo desplegable como lo explica el third answer here. Sin embargo, si CUALQUIER OTRO campo no relacionado arroja un error, entonces los datos se pierden, porque el menú desplegable deshabilitado nunca envió ningún dato a POST en primer lugar.

Es una situación complicada.

¿Hay alguna manera de pasar los datos dentro de la vista a la solicitud.POST? ¿o qué sugieres? Podría usar un readonly en lugar de disabled y eso funcionaría; sin embargo, el menú desplegable puede ser modificado por el usuario, lo que también es irritante.

¿Alguna idea? Muchas Gracias

edición:

pequeña corrección: Los datos no se pierde por completo. Más bien, la selección se establece incorrectamente al valor ficticio inicial.

<select id="id_form-0-deal_type" name="form-0-deal_type" disabled="disabled"> 
     <option selected="selected" value="">---------</option> 
     <option value="1">deal 1</option> 
     <option value="2">deal 2</option> 
    </select> 

ACTUALIZACIÓN:

La solución de Francis parece muy prometedor. Así que probé su segunda sugerencia y agregué un campo de entrada oculto en el html y le pasé el valor correcto al POST.

El problema ahora es cómo proceder. He tratado de agregar la entrada faltante en querydict de la forma del juego de formularios así (con el fin de establecer el valor desplegable correcta)

formset.forms[0].data['form-0-deal_type'] = formset.forms[0].data['form-0-hiddenfield'] 

Pero dice This QueryDict instance is immutable

La única manera de hacerlo es establecer que a través de Initials con formularios regulares. Desgraciadamente, estoy usando modelformsets, que doesn't support initials para formularios existentes.

Si no hay otra solución, comienzo a refactorizar mi modelformset en un formset regular. Todavía abierto para ideas ...

Informe final de actualización + Solución:

No hay necesidad de refactorizar modelformset en fomsets regulares. De hecho, no me gusta mucho hacer eso, ya que trae otros problemas consigo mismo. modelformsets maneja todo por ti y llena las partes faltantes.

El problema real es el hecho de que QueryDict son inmutables, pero esto se puede solucionar fácilmente copiándolos:

formset = deal_formset(request.POST, queryset=formset_query)   
if formset.is_valid(): 
    pass 
else: 
    new_post = request.POST.copy() 
    deal_types = dict() 
    for k,v in new_post.items(): 
    if k.startswith('hidden'): 
     deal_types[k[7:]]= v 
    for k,v in deal_types.iteritems(): 
    new_post[k] = v 
    formset = deal_formset(new_post, queryset=formset_query) 

Esto, más la solución de Francisco:

{{ formset.management_form }} 
    {% for fs in formset %} 
    {{ fs.id }} 
    <input type="hidden" name="hidden-{{ fs.prefix }}-deal_type" value="{{fs.deal_type.value}}" /> 
    {{fs.deal_type}} 
{% endfor %} 
{% endif %} 

solo hace maravillas. .. disfruta :)

+1

"La información no se pierde por completo.Más bien, la selección se establece incorrectamente en el valor ficticio inicial. "- eso es b/c ese campo no se publica, por lo que se usa el valor predeterminado –

Respuesta

17

No es algo de django, es algo de HTML. Los elementos de formulario deshabilitados no se envían por el formulario.

[The Element] no puede recibir la entrada del usuario ni su valor se presentará con el formulario.

http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1 & http://www.w3schools.com/tags/att_input_disabled.asp

podría utilizar readonly si es en un texto/área de texto http://www.w3schools.com/tags/att_input_readonly.asp

otra cosa que podría hacer, es mostrar el texto en claro valor, y lo presentará como un campo oculto. ...

{{ form.field_name.label_tag }} 
{{ form.field_name.value }} 
<input type="hidden" name="field_name" value="{{form.field_name.value}}" /> 

no es muy elegante, pero podría conseguir y aquí afuera.

También podría ir un paso más allá y escribir algunos JS que busquen elementos deshabilitados y luego agregue una entrada con el nombre y el valor de ese elemento.

algunos ejemplos de jQuery:

//Untested, but you get the gist 
$(':disabled').each(
    function() 
    { 
     $(this).after('<input type="hidden" name="' + $(this).attr('name') + '" value="' + $(this).val() + '" />'); 
    } 
); 
+0

Gracias Francis. Gran solución. Consulte mi pregunta actualizada con algunos detalles. Gracias – Houman

0

Creo que este es un problema de HTML en lugar de Django, campos de formulario con discapacidad no publican sus valores de nuevo por lo que está perdiendo el valor.

¿Sería posible volver a enlazar el valor al campo si falla la validación? Se podría intentar algo así como

if form.is_valid(): # All validation rules pass 
    #save form, redirect, etc. 
else: 
    form.disabled_field = my_value 
return render(request, 'contact.html', {'form': form,}) 

Obviamente tendrá que reemplazar el nombre de campo y el valor con los datos correctos de su modelo.

1

Bueno, podría configurar el elemento con propiedad oculta en la plantilla, el uso de juegos de formularios en la vista de la construcción de la forma:

{{form.field.as_hidden}} 

y dentro de la vista, si el problema es la pérdida de datos, usted podría siempre establezca un valor inicial para el campo que se adapte a la estructura de su modelo, ya que es una clave externa. Por supuesto, tendrá que validar el formulario antes de comprometerlo, y si el formulario no es válido, puede representarlo con valores iniciales en los campos que siempre deben cumplimentarse.

+0

Me gusta la idea. No entendí la parte oculta, porque claramente pierdo la selección predeterminada. Por lo tanto, tengo que volver a enviarla de alguna manera a la vista. Logré hacer eso con las sugerencias de Francis de un campo de entrada oculto adicional. Y a partir de ahí estaba pensando en las iniciales de los conjuntos de formularios. :) Por favor, eche un vistazo a mi pregunta actualizada. Gracias :) – Houman

+1

¡Excelente! Voy a mantener esta pregunta en mis favoritos, porque podría manejar una situación como esa en el futuro ! –

Cuestiones relacionadas