2012-07-31 13 views
10

Ho un menu a discesa in un modello e l'utente non dovrebbe essere in grado di modificare il valore selezionato. Ho trovato che un disabled fa esattamente ciò di cui ho bisogno. Tuttavia c'è una stranezza in questo:Django: menu a discesa disattivato non invia informazioni al POST

La prima volta che si apre il modulo (GET) il valore è selezionato e l'utente non può modificare il valore. che è grande:

enter image description here

Ma non appena v'è un errore di convalida con una unrelated field e il POST invia l'utente alla stessa forma, le informazioni precedenti si perde. Il menu a discesa foreignkey disabled non contiene più alcun valore ed è molto irritante.

enter image description here

ho fatto qualche ricerca e ho trovato qualcosa su StackOverflow e sembra quando un widget ForeignKey-discesa è disattivato, i dati non vengono inviati indietro a tutti. Mentre la convalida può essere annullata per non generare alcun errore per il campo a discesa come spiegato da third answer here. Tuttavia, se QUALSIASI ALTRA campo non correlato genera un errore, i dati vengono persi, poiché il menu a discesa disabilitato non ha mai inviato alcun dato al POST al primo posto.

È una situazione complicata.

C'è un modo per passare i dati all'interno della vista alla richiesta.POST? o cosa suggerisci? Potrei usare uno readonly invece di disabled e ciò funzionerebbe, tuttavia il dropdown può essere modificato dall'utente, che è anche irritante.

Qualche idea? Molte grazie

edit:

Piccola correzione: I dati non è completamente perso. Piuttosto, la selezione è impostata erroneamente sul valore fittizio iniziale.

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

UPDATE:

La soluzione da Francesco sembra molto promettente. Così ho provato il suo secondo suggerimento e ho aggiunto un campo di input nascosto nell'html e ho inserito il valore corretto nel POST.

Il problema è ora come procedere. Ho provato ad aggiungere la voce mancante in QueryDict del modulo del formset come questo (al fine di impostare il valore a discesa corretto)

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

ma dice This QueryDict instance is immutable

L'unico altro modo per farlo è la creazione di esso attraverso Initials con formulari regolari. Purtroppo sto usando modelformsets, che è doesn't support initials per i moduli esistenti.

Se non c'è altra soluzione, inizio a refactoring myformformset in un formset regolare. Ancora aperto alle idee ...

aggiornamento finale + Soluzione:

Non v'è alcuna necessità di refactoring modelformset in fomsets regolari. In effetti, lo scoraggio molto, poiché porta altri problemi con se stesso. modelformsets gestisce tutto per te e riempie le parti mancanti.

Il vero problema è il fatto che QueryDict sono immutabili, ma questo può essere facilmente risolto copiandoli:

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) 

Questo, più la soluzione di Francesco:

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

funziona a meraviglia. .. enjoy :)

+1

"I dati non sono completamente persi.Piuttosto, la selezione è impostata erroneamente sul valore fittizio iniziale. "- che è b/c che il campo non viene pubblicato, quindi viene utilizzato il valore predefinito –

risposta

17

Non è una cosa da django, è una cosa HTML. Gli elementi del modulo disabilitati non vengono inviati dal modulo.

[L'elemento] non può ricevere input dell'utente né il suo valore verrà inviato con il modulo.

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

è possibile utilizzare readonly se su un testo/textarea http://www.w3schools.com/tags/att_input_readonly.asp

qualcos'altro si potrebbe fare, è mostrare il testo in chiaro il valore e lo presenta come un campo nascosto. ...

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

non è molto elegante, ma potrebbe ottenere y o là.

Si potrebbe anche fare un ulteriore passo avanti e scrivere un JS che cerca elementi disabilitati e aggiunge un input con il nome e il valore di quell'elemento dopo.

qualche esempio JQuery:

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

Grazie Francesco. Ottima soluzione. Consulta la mia domanda aggiornata con alcuni dettagli. Grazie – Houman

0

Credo che questo sia un problema, piuttosto che HTML Django, disabili campi di modulo non pubblicare i loro valori indietro in modo che stai perdendo il valore.

Sarebbe possibile riassociare il valore sul campo se la convalida non riesce? Si potrebbe provare qualcosa di simile

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,}) 

Ovviamente è necessario sostituire il nome del campo e il valore con i dati corretti dal vostro modello.

1

Beh, si potrebbe impostare l'elemento con la proprietà nascosta nel modello, utilizzando formsets nella visualizzazione di costruire la forma:

{{form.field.as_hidden}} 

e all'interno della vista, se il problema è la perdita di dati, si potrebbe imposta sempre un valore iniziale per il campo adatto alla struttura del tuo modello, poiché è una chiave esterna. Naturalmente, dovrai convalidare il modulo prima di eseguirlo e, se il modulo non è valido, puoi renderlo con i valori iniziali sui campi che devono essere sempre riempiti.

+0

Mi piace l'idea: non ho capito la parte nascosta, perché sto chiaramente perdendo la selezione predefinita, quindi ho bisogno di inviarlo in qualche modo alla vista, sono riuscito a farlo con i suggerimenti di Francis di un campo di input nascosto extra. E da lì stavo pensando alle iniziali su formset. :) Per favore, dai un'occhiata alla mia domanda aggiornata Grazie :) – Houman

+1

Eccellente, terrò questa domanda nei miei preferiti, perché potrei affrontare una situazione del genere in futuro ! –

Problemi correlati