Django ustawia wartość pola po zainicjowaniu formularza


116

Próbuję ustawić pole na określoną wartość po zainicjowaniu formularza.

Na przykład mam następującą klasę.

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

W widoku chcę móc zrobić coś takiego:

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

return HttpResponse(t.render(c))

Odpowiedzi:


135

Ponieważ nie przekazujesz danych POST, zakładam, że próbujesz ustawić wartość początkową, która zostanie wyświetlona w formularzu. Sposób, w jaki to robisz, polega na użyciu initialsłowa kluczowego.

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

Więcej wyjaśnień znajdziesz w dokumentacji Django Form .

Jeśli próbujesz zmienić wartość po przesłaniu formularza, możesz użyć czegoś takiego:

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

Więcej informacji na temat używania można znaleźć w wymienionych powyżej dokumentach cleaned_data


2
Potwierdza to, co wiedziałem, ale mój ModelChoiceFieldnadal daje invalid_choice, kiedy initial
nadaję

Tak, to też mój problem. A zmiana form.data ['Email'] nie jest możliwa.
GergelyPolonkai

2
zmieniłem moje na form.data['Email'] = GetEmailString()i działa
psychok7

1
Muszę ustawić go między CustomForm (request.POST) i .is_valid (), więc nie mogę użyć ani początkowego w konstruktorze, ani czyszczonych_danych. Próbowałem użyć form.data, ale jest niezmienny (Django 1.11).
Teekin

Prawidłowe rozwiązanie na to pytanie, powinno być: daje dostęp do zainicjować swoje wartości nawet po instanciated formularzaform.fields['Email'].initial = GetEmailString()form.fields['keyword'].initial
vctrd

95

Jeśli formularz został już zainicjowany, możesz użyć początkowej właściwości pola. Na przykład,

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

Świetnie sprawdza się również w pętli for z zestawem formularzy, po prostu użyj logiki „for form in formset” i możesz ustawić opcje i początkowe dane, jak pokazano powyżej.
radtek

5
Czy można to zrobić inaczej w Django 1.7 / Python 3.4? To nie działa dla mnie
Jeremy

1
@JeremyCraigMartinez: Nie ... Czy formularz, który próbujesz, jest formularzem powiązanym (z przekazanymi danymi GET / POST)? Dokumenty mówią, że dlatego wartości początkowe są wyświetlane tylko dla niezwiązanych formularzy. W przypadku formularzy powiązanych dane wyjściowe HTML będą używać powiązanych danych. , patrz tutaj
Markus,

9
prawidłowy sposób to form.initial ["Email"] = GetEmailString ()
Elio Scordo

12

Jeśli __init__z jakiegoś powodu chcesz to zrobić w ramach metody formularza , możesz manipulować initialdyktowaniem:

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'

Wreszcie znalazłem rozwiązanie. Dziękuję Ci. U mnie to zadziałało.
Almas Dusal

8

Coś w rodzaju Nigela Cohena zadziałałoby, gdybyś dodawał dane do kopii zebranego zestawu danych formularza:

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

1
Nie jestem wielkim fanem zastępowania surowych danych. Jeśli absolutnie musisz to zrobić, prawdopodobnie powinieneś to zrobić, data[form.add_prefix('Email')]aby uwzględnić przypadki, w których ustawiono prefiks.
Josh

2
Czy można to zrobić inaczej w Django 1.7 / Python 3.4? To nie działa dla mnie
Jeremy

Trzecia linia może być trochę krótsza, jeśli nie ma potrzeby zachowania oryginalnej formy:form.data = form.data.copy()
ZZY

@Josh, oto jeden scenariusz potrzeby: użyj formularza do walidacji danych wejściowych -> przetwarzanie z danymi wejściowymi -> przetwarzanie zakończone -> usuń / zmodyfikuj kilka pól formularza i renderuj do HTML jako odpowiedź. Przykład: w formularzu znajdują się pola „imię i nazwisko”, „e-mail”, „treść”. Chcę zachować pola „imię i nazwisko” i „adres e-mail”, ale usunąć „treść”. Aby użytkownicy nie musieli ponownie wpisywać nazwy / adresu e-mail, jeśli chcą przesłać kolejny POST. Oczywiście zainicjuj nowy formularz z taką samą nazwą /
adresem

Nie jestem pewien, czy w pełni rozumiem. Jednak jeśli to zrobię, wydaje mi się, że powinieneś zamiast tego używać modelform_factory. W ten sposób możesz wygenerować klasę Form, która nie ma pól, których nie chcesz. Bardzo niebezpieczne jest posiadanie klasy Form, która zawiera pola, które nie są renderowane, ponieważ obiekt formularza nadal będzie akceptował dane dla pól niewyrenderowanych. Atakujący może to wykorzystać na swoją korzyść.
Josh

5

Jeśli zainicjowałeś formularz w ten sposób

form = CustomForm()

to prawidłowy sposób od stycznia 2019 r. polega na użyciu .initialdo zastąpienia danych. Spowoduje to zastąpienie danych w intialdictwie, które są zgodne z formularzem. Działa również, jeśli zainicjowałeś przy użyciu jakiejś instancji, takiej jak form = CustomForm(instance=instance)

Aby zamienić dane w formularzu, musisz

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

Uogólniając to byłoby,

form.initial['field_name'] = new_value

3

Po prostu zmień swoje pole 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

Aby rzucić jeszcze jedną drogę do miksu: to też działa, z nieco nowocześniejszą notacją. Po prostu działa wokół faktu, że a QueryDictjest niezmienny.

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

w widgecie użyj atr. „wartość”. Przykład:

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

-12

Możesz to zrobić w inny sposób, jeśli już zainicjowałeś formularz (z danymi lub bez) i musisz dodać dalsze dane przed jego wyświetleniem:

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

8
To mi się nie udaje. Mam wiersz podobny do powyższego w metodzie init mojego formularza i wywołuje on „AttributeError: This QueryDict instance is immutable”
Jonathan Hartley

Ten kod działa tylko wtedy, gdy formularz został zainicjowany bez żadnych danych formularza. W rezultacie niezmienny obiekt, taki jak request.GET lub request.POST, nie zostanie powiązany, więc otrzymasz pusty słownik (form.data), który można zmienić bez żadnych błędów. FYI Używam Django 1.6.3
potar

To zadziała, jeśli nagłówek „Content-Type” jest ustawiony na „multipart / form-data”. Nie udaje się, jeśli używasz typu zawartości „application / x-www-form-urlencoded”. Nie wiem dlaczego, ale debugowanie było *****.
teewuane
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.