Dalam bentuk Django, bagaimana cara membuat bidang hanya baca (atau dinonaktifkan)?
Ketika formulir sedang digunakan untuk membuat entri baru, semua bidang harus diaktifkan - tetapi ketika catatan dalam mode pembaruan, beberapa bidang harus hanya-baca.
Misalnya, saat membuat Item
model baru , semua bidang harus dapat diedit, tetapi saat memperbarui catatan, apakah ada cara untuk menonaktifkan sku
bidang sehingga terlihat, tetapi tidak dapat diedit?
class Item(models.Model):
sku = models.CharField(max_length=50)
description = models.CharField(max_length=200)
added_by = models.ForeignKey(User)
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ('added_by')
def new_item_view(request):
if request.method == 'POST':
form = ItemForm(request.POST)
# Validate and save
else:
form = ItemForm()
# Render the view
Bisakah kelas ItemForm
digunakan kembali? Perubahan apa yang akan diperlukan di kelas model ItemForm
atau Item
? Apakah saya perlu menulis kelas lain, " ItemUpdateForm
", untuk memperbarui item?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
Jawaban:
Seperti yang ditunjukkan dalam jawaban ini , Django 1.9 menambahkan atribut Field.disabled :
Dengan Django 1.8 dan yang lebih lama, untuk menonaktifkan entri pada widget dan mencegah peretasan POST berbahaya, Anda harus menggosok input selain mengatur
readonly
atribut pada bidang formulir:Atau, ganti
if instance and instance.pk
dengan kondisi lain yang menunjukkan Anda sedang mengedit. Anda juga bisa mengatur atributdisabled
pada kolom input, bukanreadonly
.The
clean_sku
fungsi akan memastikan bahwareadonly
nilai tidak akan ditimpa olehPOST
.Jika tidak, tidak ada bidang formulir Django built-in yang akan memberikan nilai sambil menolak data input terikat. Jika ini yang Anda inginkan, Anda harus membuat yang terpisah
ModelForm
yang mengecualikan bidang yang tidak dapat diedit, dan cukup mencetaknya di dalam templat Anda.sumber
clean_description
metode ke kelas bentuk.disabled
ditambahkan dalam Django 1.9. JikaField.disabled
diatur keTrue
, maka nilai POST untuk ituField
diabaikan. Jadi, jika Anda menggunakan 1.9, tidak perlu menimpaclean
, cukup aturdisabled = True
. Periksa jawaban ini .Django 1.9 menambahkan atribut Field.disabled: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled
sumber
disabled=True
akan menyebabkan model menjadi meludah ke pengguna dengan kesalahan validasi.Pengaturan
readonly
pada widget hanya membuat input di browser hanya-baca. Menambahkanclean_sku
pengembalian yanginstance.sku
memastikan nilai bidang tidak akan berubah pada level formulir.Dengan cara ini Anda dapat menggunakan model (simpan yang tidak dimodifikasi) dan menghindari kesalahan yang diperlukan bidang.
sumber
return self.cleaned_data['sku']
akan sebaik atau lebih baik? The docs tampaknya menyarankan menggunakancleaned_data
: "Nilai kembali dari metode ini menggantikan nilai yang ada dicleaned_data
, sehingga harus menjadi nilai bidang ini daricleaned_data
(bahkan jika metode ini tidak mengubahnya) atau nilai dibersihkan baru."jawaban awalker banyak membantu saya!
Saya telah mengubah contohnya untuk bekerja dengan Django 1.3, menggunakan get_readonly_fields .
Biasanya Anda harus mendeklarasikan sesuatu seperti ini di
app/admin.py
:Saya telah beradaptasi dengan cara ini:
Dan itu bekerja dengan baik. Sekarang jika Anda menambahkan Item,
url
bidang ini baca-tulis, tetapi saat diubah itu menjadi hanya-baca.sumber
Untuk membuat ini berfungsi untuk
ForeignKey
bidang, beberapa perubahan perlu dilakukan. Pertama,SELECT HTML
tag tidak memiliki atribut readonly. Kita harus menggunakandisabled="disabled"
sebagai gantinya. Namun, maka browser tidak mengirim data formulir apa pun untuk bidang itu. Jadi kita perlu mengatur bidang itu agar tidak diperlukan agar bidang tersebut divalidasi dengan benar. Kami kemudian perlu mengatur ulang nilai kembali ke tempat semula sehingga tidak disetel ke kosong.Jadi untuk kunci asing Anda perlu melakukan sesuatu seperti:
Dengan cara ini browser tidak akan membiarkan pengguna mengubah bidang, dan akan selalu
POST
seperti itu dibiarkan kosong. Kami kemudian mengganticlean
metode untuk menetapkan nilai bidang menjadi apa yang awalnya dalam contoh.sumber
TabularInline
, tetapi gagal karenaattrs
dibagikan di antarawidget
instance dan semua kecuali baris pertama, termasuk yang baru ditambahkan, hanya dibaca yang dibuat.Untuk Django 1.2+, Anda dapat mengganti bidang seperti:
sumber
Field
disabled
tidak melakukan apa yang saya inginkan karena menonaktifkan bidang, tetapi juga menghilangkan label / membuatnya tidak terlihat.Saya membuat kelas MixIn yang dapat Anda warisi untuk dapat menambahkan bidang read_only iterable yang akan menonaktifkan dan mengamankan bidang pada pengeditan non-pertama:
(Berdasarkan jawaban Daniel dan Muhuk)
sumber
Saya baru saja membuat widget sesederhana mungkin untuk bidang hanya baca - Saya tidak benar-benar mengerti mengapa formulir belum memiliki ini:
Dalam bentuk:
Sangat sederhana - dan hanya membuat saya output. Berguna dalam format dengan banyak nilai hanya baca. Tentu saja - Anda juga bisa menjadi sedikit lebih pintar dan memberikan div dengan attrs sehingga Anda dapat menambahkan kelas ke dalamnya.
sumber
unicode(value)
sebagai gantinya mungkin. Dengan anggapan unicode dunder masuk akal, Anda akan mendapatkannya.Saya menemukan masalah yang sama. Sepertinya saya bisa menyelesaikannya dengan mendefinisikan metode "get_readonly_fields" di kelas ModelAdmin saya.
Sesuatu seperti ini:
Yang menyenangkan adalah itu
obj
akan ada ketika Anda menambahkan item baru, atau itu akan menjadi objek yang sedang diedit ketika Anda mengubah item yang sudah ada.get_readonly_display didokumentasikan di sini: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods
sumber
Salah satu opsi sederhana adalah dengan mengetikkan
form.instance.fieldName
templat alih-alihform.fieldName
.sumber
verbos_name
ataulabel
lapangan? Bagaimana saya bisa menampilkan `label dalam template Django? @alzclarkeBagaimana saya melakukannya dengan Django 1.11:
sumber
Sebagai tambahan yang berguna untuk posting Humphrey , saya memiliki beberapa masalah dengan Django-reversion, karena masih mendaftarkan bidang yang dinonaktifkan sebagai 'diubah'. Kode berikut memperbaiki masalah.
sumber
Karena saya belum bisa berkomentar ( solusi muhuk ), saya akan menjawab sebagai jawaban terpisah. Ini adalah contoh kode lengkap, yang berfungsi untuk saya:
sumber
Sekali lagi, saya akan menawarkan satu solusi lagi :) Saya menggunakan kode Humphrey , jadi ini didasarkan pada itu.
Namun, saya mengalami masalah dengan bidang yang menjadi a
ModelChoiceField
. Semuanya akan bekerja berdasarkan permintaan pertama. Namun, jika formset mencoba menambahkan item baru dan gagal validasi, ada yang salah dengan formulir "yang ada" di manaSELECTED
opsi sedang diatur ulang ke default---------
.Lagi pula, saya tidak tahu bagaimana cara memperbaikinya. Jadi sebagai gantinya, (dan saya pikir ini sebenarnya lebih bersih dalam bentuk), saya membuat ladang
HiddenInputField()
. Ini berarti Anda harus melakukan sedikit lebih banyak pekerjaan di template.Jadi perbaikan untuk saya adalah menyederhanakan Formulir:
Dan kemudian di templat, Anda harus melakukan beberapa perulangan manual dari formset .
Jadi, dalam hal ini Anda akan melakukan sesuatu seperti ini di templat:
Ini bekerja sedikit lebih baik untuk saya dan dengan manipulasi bentuk yang lebih sedikit.
sumber
Saya mengalami masalah yang sama jadi saya membuat Mixin yang sepertinya berfungsi untuk kasus penggunaan saya.
Penggunaan, cukup tentukan yang mana yang harus dibaca saja:
sumber
'collections.OrderedDict' object has no attribute 'iteritems'
jika Anda membutuhkan beberapa bidang baca-saja. Anda dapat menggunakan salah satu metode yang diberikan di bawah ini
metode 1
metode 2
metode pewarisan
sumber
Dua lagi pendekatan (serupa) dengan satu contoh umum:
1) pendekatan pertama - menghapus bidang dalam metode save (), mis. (Tidak diuji;)):
2) pendekatan kedua - setel ulang bidang ke nilai awal dalam metode bersih:
Berdasarkan pendekatan kedua saya menggeneralisasikannya seperti ini:
sumber
Untuk versi Admin, saya pikir ini adalah cara yang lebih ringkas jika Anda memiliki lebih dari satu bidang:
sumber
Berdasarkan jawaban Yamikep , saya menemukan solusi yang lebih baik dan sangat sederhana yang juga menangani
ModelMultipleChoiceField
bidang.Menghapus bidang dari
form.cleaned_data
mencegah bidang disimpan:Pemakaian:
sumber
Ini adalah versi yang sedikit lebih terlibat, berdasarkan jawaban christophe31 . Itu tidak bergantung pada atribut "readonly". Ini membuat masalah, seperti kotak pilih masih dapat diubah dan datapickers masih muncul, pergi.
Alih-alih, itu membungkus widget bidang formulir di widget hanya baca, sehingga membuat formulir masih valid. Konten widget asli ditampilkan di dalam
<span class="hidden"></span>
tag. Jika widget memilikirender_readonly()
metode yang digunakannya sebagai teks yang terlihat, jika tidak, ia mem-parsing HTML widget asli dan mencoba menebak representasi terbaik.sumber
Apakah ini cara paling sederhana?
Tepat di kode tampilan, kira-kira seperti ini:
Ini bekerja dengan baik!
sumber
Untuk django 1.9+
Anda bisa menggunakan argumen Fields disable untuk membuat field dinonaktifkan. misalnya Dalam cuplikan kode berikut dari file forms.py, saya telah membuat bidang employee_code dinonaktifkan
Referensi https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled
sumber
Jika Anda bekerja dengan
Django ver < 1.9
( atribut1.9
telah ditambahkanField.disabled
), Anda bisa mencoba menambahkan dekorator berikut ke__init__
metode formulir Anda :Gagasan utamanya adalah jika bidang adalah
readonly
Anda tidak memerlukan nilai lain selaininitial
.PS: Jangan lupa mengatur
yuor_form_field.widget.attrs['readonly'] = True
sumber
Jika Anda menggunakan admin Django, berikut adalah solusi paling sederhana.
sumber
Saya pikir pilihan terbaik Anda hanya akan menyertakan atribut readonly dalam template Anda yang diberikan dalam
<span>
atau<p>
bukan memasukkannya ke dalam formulir jika hanya dibaca.Formulir adalah untuk mengumpulkan data, bukan menampilkannya. Yang sedang berkata, opsi untuk menampilkan di
readonly
widget dan menggosok data POST adalah solusi bagus.sumber