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.