How can I disable a model field in a django form
Solution 1
Step 1: Disable the frontend widget
Use the HTML readonly
attribute:
http://www.w3schools.com/tags/att_input_readonly.asp
Or disabled
attribute:
http://www.w3.org/TR/html401/interact/forms.html#adef-disabled
You can inject arbitrary HTML key value pairs via the widget attrs property:
myform.fields['status'].widget.attrs['readonly'] = True # text input
myform.fields['status'].widget.attrs['disabled'] = True # radio / checkbox
Step 2: Ensure the field is effectively disabled on backend
Override your clean method for your field so that regardless of POST input (somebody can fake a POST, edit the raw HTML, etc.) you get the field value that already exists.
def clean_status(self):
# when field is cleaned, we always return the existing model field.
return self.instance.status
Solution 2
From django 1.9:
from django.forms import Textarea
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
widgets = {'my_field_in_my_model': Textarea(attrs={'cols':80,'rows':1}),}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['my_field_in_my_model'].disabled = True
Solution 3
Have you tried using the exclude function?
something like this
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title')
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
exclude = ('birth_date',)
Solution 4
Just customize the widget instance for the status field:
class MyModel(models.Model):
REGULAR = 1
PREMIUM = 2
STATUS_CHOICES = ((REGULAR, "regular"), (PREMIUM, "premium"))
name = models.CharField(max_length=30)
status = models.IntegerField(choices = STATUS_CHOICES, default = REGULAR)
class MyForm(forms.ModelForm):
status = forms.CharField(widget=forms.TextInput(attrs={'readonly':'True'}))
class Meta:
model = models.MyModel
see: Django Documentation
Solution 5
There is a very easy way of doing it:
class GenerateCertificate(models.Model):
field_name = models.CharField(
max_length=15,
editable=False)
def __unicode__(self):
return unicode(self.field_name)
The editable=False
will make the field disabled for editing.
Related videos on Youtube
jammon
Updated on August 01, 2020Comments
-
jammon over 3 years
I have a model like this:
class MyModel(models.Model): REGULAR = 1 PREMIUM = 2 STATUS_CHOICES = ((REGULAR, "regular"), (PREMIUM, "premium")) name = models.CharField(max_length=30) status = models.IntegerField(choices = STATUS_CHOICES, default = REGULAR) class MyForm(forms.ModelForm): class Meta: model = models.MyModel
In a view I initialize one field and try to make it non-editable:
myform = MyForm(initial = {'status': requested_status}) myform.fields['status'].editable = False
But the user can still change that field.
What's the real way to accomplish what I'm after?
-
jammon about 13 yearsI wanted to alter the form per instance, so
exclude
doesn't do the trick for me. -
user1066101 about 13 years@jammon: (1) "per instance" doesn't make sense. You can have several different subclasses with several different combinations of fields. (2) Please update the question to explain what you want.
-
jammon about 13 yearsOh no. I tried it, and
readonly
doesn't make a difference. And (w3schools.com/tags/att_input_readonly.asp) says 'The readonly attribute can be used with <input type="text"> or <input type="password">.' In my case it's a select or radio buttons. So any more ideas? -
Yuji 'Tomita' Tomita about 13 yearsHmm, looks like the solution with those buttons is attrs['disabled'] = True w3.org/TR/html401/interact/forms.html#adef-disabled
-
jammon about 13 yearsWorks just the way I wanted. Thank you!
-
Yuji 'Tomita' Tomita about 13 yearsNo problem jammon. If you found it satisfactory, check the checkmark next to the answer.
-
nnyby almost 9 yearsI get the error:
'BoundField' object has no attribute 'widget'
-
Roberth Solís over 6 yearsHow i can select all fields?
-
Rafi over 3 yearsfor selecting all fields: for key in self.fields.keys(): self.fields[key].widget.attrs['readonly'] = True self.fields[key].widget.attrs['disabled'] = True
-
Apollo Data over 3 yearsI was missing the clean part to maintain the value. A lifesaver, thanks!