Comme Benjamin (https://stackoverflow.com/a/2359167/565525) bien expliqué, en plus de rendre correctement, vous devez traiter le champ sur le backend correctement.
Il y a un SO question and answers qui a beaucoup de bonnes solutions. Mais de toute façon:
1) première approche - suppression du champ dans la méthode save(), par ex. (Non testé;)):
def save(self, *args, **kwargs):
for fname in self.readonly_fields:
if fname in self.cleaned_data:
del self.cleaned_data[fname]
return super(<form-name>, self).save(*args,**kwargs)
2) deuxième approche - champ remise à la valeur initiale dans la méthode propre:
def clean_<fieldname>(self):
return self.initial[<fieldname>] # or getattr(self.instance, <fieldname>)
Sur la base de la deuxième approche je l'ai généralisé comme ceci:
from functools import partial
class <Form-name>(...):
def __init__(self, ...):
...
super(<Form-name>, self).__init__(*args, **kwargs)
...
for i, (fname, field) in enumerate(self.fields.iteritems()):
if fname in self.readonly_fields:
field.widget.attrs['readonly'] = "readonly"
field.required = False
# set clean method to reset value back
clean_method_name = "clean_%s" % fname
assert clean_method_name not in dir(self)
setattr(self, clean_method_name, partial(self._clean_for_readonly_field, fname=fname))
def _clean_for_readonly_field(self, fname):
""" will reset value to initial - nothing will be changed
needs to be added dynamically - partial, see init_fields
"""
return self.initial[fname] # or getattr(self.instance, fname)
Cela a changé en django 1.9 https://stackoverflow.com/questions/324477/in-a-django-form-how -do-i-make-a-field-readonly-ou-disabled-so-that-it-ne-peut-pas- – zudebluvstein