Django menyetel nilai bidang setelah formulir diinisialisasi

116

Saya mencoba mengatur bidang ke nilai tertentu setelah formulir diinisialisasi.

Misalnya, saya memiliki kelas berikut.

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

Dalam pandangan, saya ingin dapat melakukan sesuatu seperti ini:

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

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

Jawaban:

135

Karena Anda tidak meneruskan data POST, saya akan berasumsi bahwa apa yang Anda coba lakukan adalah menyetel nilai awal yang akan ditampilkan di formulir. Cara Anda melakukannya adalah dengan initialkata kunci.

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

Lihat dokumen Django Form untuk penjelasan lebih lanjut.

Jika Anda mencoba mengubah nilai setelah formulir dikirimkan, Anda dapat menggunakan sesuatu seperti:

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

Periksa dokumen referensi di atas untuk mengetahui lebih lanjut tentang penggunaan cleaned_data

Hibah
sumber
2
Ini mengkonfirmasi apa yang saya tahu, tetapi saya ModelChoiceFieldmasih memberikan invalid_choice ketika saya memberikan initialnilai :(
markwalker_
Ya, ini masalah saya juga. Dan mengubah form.data ['Email'] tidak dimungkinkan.
GergelyPolonkai
2
saya mengubah milik saya menjadi form.data['Email'] = GetEmailString()dan berhasil
psychok7
1
Saya perlu mengaturnya antara CustomForm (request.POST) dan .is_valid (), jadi saya tidak dapat menggunakan inisial di konstruktor, atau clean_data. Saya mencoba menggunakan form.data, tetapi tidak dapat diubah (Django 1.11).
Teekin
Solusi yang tepat untuk pertanyaan ini, harus: form.fields['Email'].initial = GetEmailString() The form.fields['keyword'].initialmemberi Anda akses untuk menginisialisasi nilai-nilai Anda bahkan setelah instanciated formulir Anda
vctrd
95

Jika Anda sudah menginisialisasi formulir, Anda dapat menggunakan properti awal bidang. Sebagai contoh,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()
Josh
sumber
Juga berfungsi dengan baik di loop for dengan formset, cukup gunakan logika "for form in formset" dan Anda dapat menyetel pilihan dan data awal seperti yang terlihat di atas.
radtek
5
Apakah ada cara lain untuk melakukan ini dengan Django 1.7 / Python 3.4? Ini tidak berhasil untuk saya
Jeremy
1
@JeremyCraigMartinez: Tidak ... Apakah formulir yang Anda coba adalah formulir terikat (dengan data GET / POST yang diteruskan)? Dokumen mengatakan Inilah mengapa nilai awal hanya ditampilkan untuk formulir tidak terikat. Untuk bentuk terikat, keluaran HTML akan menggunakan data terikat. , lihat di sini
Markus
9
cara yang benar adalah form.initial ["Email"] = GetEmailString ()
Elio Scordo
12

Jika Anda ingin melakukannya dalam metode formulir __init__karena alasan tertentu, Anda dapat memanipulasi 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'
seddonim
sumber
Akhirnya ditemukan solusinya. Terima kasih. Ini berhasil untuk saya.
Almas Dusal
8

Sesuatu seperti Nigel Cohen akan bekerja jika Anda menambahkan data ke salinan dari kumpulan data formulir yang dikumpulkan:

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()
Milo P
sumber
1
Saya bukan penggemar berat menimpa data mentah. Jika Anda benar-benar harus melakukan ini, Anda mungkin harus melakukannya data[form.add_prefix('Email')]untuk memperhitungkan kasus-kasus di mana awalan ditetapkan.
Josh
2
Apakah ada cara lain untuk melakukan ini dengan Django 1.7 / Python 3.4? Ini tidak berhasil untuk saya
Jeremy
Baris ke-3 bisa sedikit lebih pendek jika tidak perlu mempertahankan bentuk aslinya:form.data = form.data.copy()
ZZY
@Josh, berikut adalah salah satu skenario kebutuhan: gunakan formulir untuk memvalidasi input -> pemrosesan dengan input -> pemrosesan selesai -> hapus / ubah beberapa bidang formulir dan render ke HTML sebagai respons. Contoh, ada kolom 'nama', 'email', 'konten' di formulir, saya ingin menyimpan 'nama' dan 'email', tetapi menghapus 'konten'. Sehingga pengguna tidak perlu memasukkan nama / email lagi, jika ingin mengirimkan POST lagi. Tentu saja menginisialisasi formulir baru dengan nama / email yang sama sebagai nilai awal adalah salah satu cara, tetapi menurut saya menghapus formulir lama lebih sederhana dalam beberapa kasus
ZZY
Saya tidak yakin saya sepenuhnya mengerti. Namun, jika saya melakukannya, bagi saya kedengarannya Anda seharusnya menggunakan modelform_factory. Dengan cara ini Anda bisa menghasilkan kelas Formulir yang tidak memiliki bidang yang tidak Anda inginkan. Sangat berbahaya memiliki kelas Formulir yang memiliki bidang yang tidak dirender karena objek formulir masih akan menerima data untuk bidang yang tidak dirender. Seorang penyerang bisa menggunakan ini untuk keuntungan mereka.
Josh
5

Jika sudah menginisialisasi form seperti ini

form = CustomForm()

Maka cara yang benar per Jan 2019 , gunakan .initialuntuk mengganti data. Ini akan menggantikan data dalam intialdikt yang sesuai dengan formulir. Ini juga berfungsi jika Anda telah menginisialisasi menggunakan beberapa contoh seperti form = CustomForm(instance=instance)

Untuk mengganti data di formulir, Anda perlu

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

Menggeneralisasi ini akan menjadi,

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

Ubah saja bidang Form.data Anda:

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.dll
sumber
0

Untuk membuang cara lain ke dalam campuran: ini juga berfungsi, dengan notasi yang sedikit lebih modern. Ini hanya bekerja di sekitar fakta bahwa a QueryDicttidak dapat diubah.

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

di widget gunakan 'nilai' attr. Contoh:

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

Cara lain untuk melakukan ini, jika Anda telah menginisialisasi formulir (dengan atau tanpa data), dan Anda perlu menambahkan data lebih lanjut sebelum menampilkannya:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()
Nigel Cohen
sumber
8
Ini gagal untuk saya. Saya memiliki garis seperti di atas dalam metode init formulir saya , dan itu memunculkan "AttributeError: Contoh QueryDict ini tidak dapat diubah"
Jonathan Hartley
Kode ini hanya berfungsi ketika formulir telah diinisialisasi tanpa data formulir apa pun. Akibatnya, objek tidak berubah seperti request.GET atau request.POST tidak akan terikat, sehingga Anda akan mendapatkan kamus kosong (form.data) yang dapat diubah tanpa kesalahan. FYI saya menggunakan Django 1.6.3
potar
Ini akan berfungsi jika header "Content-Type" Anda disetel ke "multipart / form-data". Gagal saat Anda menggunakan tipe konten "application / x-www-form-urlencoded". Saya tidak tahu mengapa, tapi itu sulit untuk di-debug.
teewuane