Django setzt den Feldwert, nachdem ein Formular initialisiert wurde

116

Ich versuche, das Feld nach der Initialisierung des Formulars auf einen bestimmten Wert zu setzen.

Zum Beispiel habe ich die folgende Klasse.

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

Aus der Sicht möchte ich in der Lage sein, so etwas zu tun:

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

return HttpResponse(t.render(c))
Eldila
quelle

Antworten:

135

Da Sie keine POST-Daten übergeben, gehe ich davon aus, dass Sie versuchen, einen Anfangswert festzulegen, der im Formular angezeigt wird. Die Art und Weise, wie Sie dies tun, ist mit dem initialSchlüsselwort.

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

Weitere Erläuterungen finden Sie in den Django Form-Dokumenten .

Wenn Sie versuchen, einen Wert nach dem Absenden des Formulars zu ändern, können Sie Folgendes verwenden:

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

Weitere Informationen zur Verwendung finden Sie in den oben genannten Dokumenten cleaned_data

Gewähren
quelle
2
Dies bestätigt, was ich wusste, aber ModelChoiceFieldich gebe immer noch invalid_choice, wenn ich ihm einen initialWert gebe :(
markwalker_
Ja, das ist auch mein Problem. Das Ändern von form.data ['Email'] ist nicht möglich.
GergelyPolonkai
2
Ich habe meine geändert form.data['Email'] = GetEmailString()und es funktioniert
Psychok7
1
Ich muss es zwischen CustomForm (request.POST) und .is_valid () einstellen, damit ich weder die Initiale im Konstruktor noch die bereinigten_Daten verwenden kann. Ich habe versucht, form.data zu verwenden, aber es ist unveränderlich (Django 1.11).
Teekin
Die richtige Lösung für diese Frage sollte lauten: form.fields['Email'].initial = GetEmailString() Mit form.fields['keyword'].initialdieser Option können Sie Ihre Werte auch nach der Instanziierung Ihres Formulars initialisieren
vctrd
95

Wenn Sie das Formular bereits initialisiert haben, können Sie die Eigenschaft initial des Felds verwenden. Beispielsweise,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()
Josh
quelle
Funktioniert auch hervorragend in einer for-Schleife mit einem Formset. Verwenden Sie einfach die Logik "for form in formset" und Sie können Auswahlmöglichkeiten und Anfangsdaten wie oben gezeigt festlegen.
Radtek
5
Gibt es eine andere Möglichkeit, dies zu tun, ist Django 1.7 / Python 3.4? Das funktioniert nicht für mich
Jeremy
1
@JeremyCraigMartinez: Nein ... Ist das Formular, das Sie versuchen, ein gebundenes Formular (mit übergebenen GET / POST-Daten)? In den Dokumenten heißt es. Aus diesem Grund werden Anfangswerte nur für ungebundene Formulare angezeigt. Bei gebundenen Formularen verwendet die HTML-Ausgabe die gebundenen Daten. , siehe hier
Markus
9
Der richtige Weg ist form.initial ["Email"] = GetEmailString ()
Elio Scordo
12

Wenn Sie dies __init__aus irgendeinem Grund innerhalb der Methode des Formulars tun möchten , können Sie das initialDiktat manipulieren :

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'
seddonym
quelle
Endlich die Lösung gefunden. Danke dir. Es hat bei mir funktioniert.
Almas Dusal
8

So etwas wie das von Nigel Cohen würde funktionieren, wenn Sie einer Kopie des gesammelten Satzes von Formulardaten Daten hinzufügen würden :

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()
Milo P.
quelle
1
Ich bin kein großer Fan davon, die Rohdaten zu überschreiben. Wenn Sie dies unbedingt tun müssen, sollten Sie wahrscheinlich data[form.add_prefix('Email')]Fälle berücksichtigen, in denen ein Präfix festgelegt ist.
Josh
2
Gibt es eine andere Möglichkeit, dies zu tun, ist Django 1.7 / Python 3.4? Das funktioniert nicht für mich
Jeremy
Die 3. Zeile kann etwas kürzer sein, wenn die ursprüngliche Form nicht form.data = form.data.copy()
beibehalten werden muss
@Josh, hier ist ein Szenario der Notwendigkeit: Verwenden Sie ein Formular, um die Eingabe zu validieren -> Verarbeitung mit der Eingabe -> Verarbeitung erfolgt -> Löschen / Ändern mehrerer Felder des Formulars und Rendern in HTML als Antwort. Beispiel: In einem Formular befinden sich die Felder "Name", "E-Mail" und "Inhalt". Ich möchte "Name" und "E-Mail" beibehalten, aber "Inhalt" löschen. Damit Benutzer den Namen / die E-Mail-Adresse nicht erneut eingeben müssen, wenn sie einen anderen POST senden möchten. Natürlich ist das Initialisieren eines neuen Formulars mit demselben Namen / derselben E-Mail-
Adresse
Ich bin mir nicht sicher, ob ich das wirklich verstehe. Wenn ich das tue, klingt es für mich jedoch so, als ob Sie stattdessen verwenden sollten modelform_factory. Auf diese Weise können Sie eine Formularklasse generieren, die nicht die Felder enthält, die Sie nicht möchten. Es ist sehr gefährlich, eine Formularklasse zu haben, deren Felder nicht gerendert werden, da das Formularobjekt weiterhin Daten für die nicht gerenderten Felder akzeptiert. Ein Angreifer könnte dies zu seinem Vorteil nutzen.
Josh
5

Wenn Sie das Formular wie folgt initialisiert haben

form = CustomForm()

dann ist der richtige Weg ab Januar 2019 , .initialdie Daten zu ersetzen. Dadurch werden die Daten im intialDiktat ersetzt, die dem Formular beiliegen. Es funktioniert auch, wenn Sie mit einer Instanz wie z form = CustomForm(instance=instance)

Um Daten im Formular zu ersetzen, müssen Sie

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

Dies zu verallgemeinern wäre,

form.initial['field_name'] = new_value
Vineeth Sai
quelle
3

Ändern Sie einfach Ihr Feld 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
ckarrie
quelle
0

Um noch einen anderen Weg in die Mischung zu werfen: Dies funktioniert auch mit einer etwas moderneren Notation. Es funktioniert nur um die Tatsache, dass a QueryDictunveränderlich ist.

>>> 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">'
DR. Sybren
quelle
0

Verwenden Sie im Widget 'value' attr. Beispiel:

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

Eine andere Möglichkeit, dies zu tun, wenn Sie bereits ein Formular (mit oder ohne Daten) initialisiert haben und weitere Daten hinzufügen müssen, bevor Sie es anzeigen:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()
Nigel Cohen
quelle
8
Das scheitert für mich. Ich habe eine Zeile wie oben in der Init- Methode meines Formulars und sie löst "AttributeError: Diese QueryDict-Instanz ist unveränderlich" aus
Jonathan Hartley
Dieser Code funktioniert nur, wenn das Formular ohne Formulardaten initialisiert wurde. Infolgedessen wird ein unveränderliches Objekt wie request.GET oder request.POST nicht gebunden, sodass Sie ein leeres Wörterbuch (form.data) erhalten, das ohne Fehler geändert werden kann. Zu
Ihrer Information
Dies funktioniert, wenn Ihr Header "Content-Type" auf "Multipart / Formulardaten" gesetzt ist. Dies schlägt fehl, wenn Sie den Inhaltstyp "application / x-www-form-urlencoded" verwenden. Ich weiß nicht warum, aber es war ein ***** zum Debuggen.
Teewuane