Django imposta il valore del campo dopo che un modulo è stato inizializzato


116

Sto cercando di impostare il campo su un determinato valore dopo che il modulo è stato inizializzato.

Ad esempio, ho la seguente classe.

class CustomForm(forms.Form):
    Email = forms.EmailField(min_length=1, max_length=200)

Nella vista, voglio essere in grado di fare qualcosa del genere:

form = CustomForm()
form["Email"] = GetEmailString()

return HttpResponse(t.render(c))

Risposte:


135

Poiché non stai passando i dati POST, presumo che quello che stai cercando di fare sia impostare un valore iniziale che verrà visualizzato nel modulo. Il modo in cui lo fai è con la initialparola chiave.

form = CustomForm(initial={'Email': GetEmailString()})

Vedere la documentazione del modulo Django per ulteriori spiegazioni.

Se stai tentando di modificare un valore dopo che il modulo è stato inviato, puoi utilizzare qualcosa come:

if form.is_valid():
    form.cleaned_data['Email'] = GetEmailString()

Controlla i documenti di riferimento sopra per ulteriori informazioni sull'utilizzo cleaned_data


2
Ciò conferma ciò che sapevo, ma ModelChoiceFieldcontinuo a dare invalid_choice quando gli do un initialvalore :(
markwalker_

Sì, anche questo è il mio problema. E la modifica di form.data ["Email"] non è possibile.
GergelyPolonkai

2
ho cambiato il mio in form.data['Email'] = GetEmailString()e funziona
psychok7

1
Devo impostarlo tra CustomForm (request.POST) e .is_valid (), quindi non posso usare l'iniziale nel costruttore, né il clean_data. Ho provato a usare form.data, ma è immutabile (Django 1.11).
Teekin

La soluzione corretta a questa domanda, dovrebbe essere: form.fields['Email'].initial = GetEmailString() il form.fields['keyword'].initialconsente l'accesso inizializzare i vostri valori, anche dopo aver istanziare la vostra forma
vctrd

95

Se hai già inizializzato il modulo, puoi utilizzare la proprietà iniziale del campo. Per esempio,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()

Funziona benissimo anche in un ciclo for con un formset, basta usare la logica "for form in formset" e puoi impostare scelte e dati iniziali come visto sopra.
radtek

5
C'è un modo diverso per farlo è Django 1.7 / Python 3.4? Questo non funziona per me
Jeremy il

1
@ JeremyCraigMartinez: No ... il modulo che stai provando è un modulo associato (con i dati GET / POST passati)? I documenti dicono che questo è il motivo per cui i valori iniziali vengono visualizzati solo per i moduli non associati. Per i moduli associati, l'output HTML utilizzerà i dati associati. , vedi qui
Markus

9
il modo corretto è form.initial ["Email"] = GetEmailString ()
Elio Scordo

12

Se vuoi farlo all'interno del __init__metodo del form per qualche motivo, puoi manipolare il initialdict:

class MyForm(forms.Form):
    my_field = forms.CharField(max_length=255)

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.initial['my_field'] = 'Initial value'

Finalmente ho trovato la soluzione. Grazie. Ha funzionato per me.
Almas Dusal

8

Qualcosa di simile a Nigel Cohen funzionerebbe se si aggiungessero dati a una copia del set di dati del modulo raccolto:

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()

1
Non sono un grande fan dell'override dei dati grezzi. Se devi assolutamente farlo, probabilmente dovresti farlo data[form.add_prefix('Email')]per tenere conto dei casi in cui è impostato un prefisso.
Josh

2
C'è un modo diverso per farlo è Django 1.7 / Python 3.4? Questo non funziona per me
Jeremy

La terza riga può essere un po 'più corta se non è necessario mantenere la forma originale:form.data = form.data.copy()
ZZY

@ Josh, ecco uno scenario della necessità: utilizzare un modulo per convalidare l'input -> elaborazione con l'input -> elaborazione eseguita -> cancella / modifica diversi campi del modulo e restituisci in HTML come risposta. Ad esempio, ci sono campi "nome", "email", "contenuto" in un modulo, desidero mantenere "nome" e "email", ma cancellare "contenuto". In modo che gli utenti non debbano inserire nuovamente nome / e-mail, se vogliono inviare un altro POST. Ovviamente inizializzare un nuovo modulo con lo stesso nome / e-mail del valore iniziale è un modo, ma penso che cancellare il vecchio modulo sia più semplice in alcuni casi
ZZY

Non sono sicuro di aver capito appieno. Tuttavia, se lo faccio, mi sembra che dovresti invece usare modelform_factory. In questo modo puoi generare una classe Form che non ha i campi che non desideri. È molto pericoloso avere una classe Form con campi che non vengono visualizzati poiché l'oggetto modulo accetterà comunque i dati per i campi non sottoposti a rendering. Un attaccante potrebbe usarlo a proprio vantaggio.
Josh

5

Se hai inizializzato il modulo in questo modo

form = CustomForm()

quindi il modo corretto a partire da gennaio 2019 , è quello .initialdi sostituire i dati. Questo sostituirà i dati nel intialdict che accompagna il modulo. Funziona anche se hai inizializzato utilizzando un'istanza come form = CustomForm(instance=instance)

Per sostituire i dati nel modulo, è necessario

form.initial['Email'] = GetEmailString()

Generalizzando questo sarebbe,

form.initial['field_name'] = new_value

3

Basta modificare il campo Form.data:

class ChooseProjectForm(forms.Form):
    project = forms.ModelChoiceField(queryset=project_qs)
    my_projects = forms.BooleanField()

    def __init__(self, *args, **kwargs):
        super(ChooseProjectForm, self).__init__(*args, **kwargs)
        self.data = self.data.copy()  # IMPORTANT, self.data is immutable
        # any condition:
        if self.data.get('my_projects'):
            my_projects = self.fields['project'].queryset.filter(my=True)
            self.fields['project'].queryset = my_projects
            self.fields['project'].initial = my_projects.first().pk
            self.fields['project'].empty_label = None  # disable "-----"
            self.data.update(project=my_projects.first().pk)  # Update Form data
            self.fields['project'].widget = forms.HiddenInput()  # Hide if you want

0

Per aggiungere un altro modo al mix: funziona anche questo, con una notazione un po 'più moderna. Funziona solo intorno al fatto che a QueryDictè immutabile.

>>> the_form.data = {**f.data.dict(), 'some_field': 47}
>>> the_form['some_field'].as_widget()
'<input type="hidden" name="some_field" value="47"
        class="field-some_field" id="id_some_field">'

0

nel widget usa 'valore' attr. Esempio:

username = forms.CharField(
    required=False,
    widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
)

-12

Un altro modo per farlo, se hai già inizializzato un modulo (con o senza dati) e devi aggiungere ulteriori dati prima di visualizzarlo:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()

8
Questo fallisce per me. Ho una riga come quella sopra nel metodo init del mio modulo e solleva "AttributeError: questa istanza di QueryDict è immutabile"
Jonathan Hartley

Questo codice funziona solo quando il modulo è stato inizializzato senza alcun dato del modulo. Di conseguenza, un oggetto immutabile come request.GET o request.POST non verrà associato, quindi otterrai un dizionario vuoto (form.data) che può essere modificato senza errori. Cordiali saluti, sto usando Django 1.6.3
potar

Questo funzionerà se la tua intestazione "Content-Type" è impostata su "multipart / form-data". Non riesce quando si utilizza un tipo di contenuto "application / x-www-form-urlencoded". Non so perché, ma è stato un ***** eseguire il debug.
teewuane
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.