from django import forms
from django.utils.safestring import mark_safe
class SpanWidget(forms.Widget):
'''Renders a value wrapped in a <span> tag.
Requires use of specific form support. (see ReadonlyForm
or ReadonlyModelForm)
'''
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<span%s >%s</span>' % (
forms.util.flatatt(final_attrs), self.original_value))
def value_from_datadict(self, data, files, name):
return self.original_value
class SpanField(forms.Field):
'''A field which renders a value wrapped in a <span> tag.
Requires use of specific form support. (see ReadonlyForm
or ReadonlyModelForm)
'''
def __init__(self, *args, **kwargs):
kwargs['widget'] = kwargs.get('widget', SpanWidget)
super(SpanField, self).__init__(*args, **kwargs)
class Readonly(object):
'''Base class for ReadonlyForm and ReadonlyModelForm which provides
the meat of the features described in the docstings for those classes.
'''
class NewMeta:
readonly = tuple()
def __init__(self, *args, **kwargs):
super(Readonly, self).__init__(*args, **kwargs)
readonly = self.NewMeta.readonly
if not readonly:
return
for name, field in self.fields.items():
if name in readonly:
field.widget = SpanWidget()
elif not isinstance(field, SpanField):
continue
field.widget.original_value = str(getattr(self.instance, name))
class ReadonlyForm(Readonly, forms.Form):
'''A form which provides the ability to specify certain fields as
readonly, meaning that they will display their value as text wrapped
with a <span> tag. The user is unable to edit them, and they are
protected from POST data insertion attacks.
The recommended usage is to place a NewMeta inner class on the
form, with a readonly attribute which is a list or tuple of fields,
similar to the fields and exclude attributes on the Meta inner class.
class MyForm(ReadonlyForm):
foo = forms.TextField()
class NewMeta:
readonly = ('foo',)
'''
pass
class ReadonlyModelForm(Readonly, forms.ModelForm):
'''A ModelForm which provides the ability to specify certain fields as
readonly, meaning that they will display their value as text wrapped
with a <span> tag. The user is unable to edit them, and they are
protected from POST data insertion attacks.
The recommended usage is to place a NewMeta inner class on the
form, with a readonly attribute which is a list or tuple of fields,
similar to the fields and exclude attributes on the Meta inner class.
class Foo(models.Model):
bar = models.CharField(max_length=24)
class MyForm(ReadonlyModelForm):
class Meta:
model = Foo
class NewMeta:
readonly = ('bar',)
'''
pass
Comments
It does not work on DateTime fields unfortunately. The error is the same as in the snippet Readonly admin fields
#
Hi,
it works for me with dropdown lists and text fields.
how can I make it work with checkboxes?
Thanks.
#
This is not working at all for me. It works "fine" up until I try to save a modelform with some fields as read-only. Something in the system tries to verify the readonly fields and I am getting errors.
I'm new to django, and since no one else is complaining about this perhaps it's my code, but I can't figure it out.
#
This doesn't work at all, at least not the base Readonly object, without a ModelForm.
The base Form class doesn't have an 'instance' property.
#
It's even a bit trickier than that; this won't work with initial data, either; you have to actually populate the form with data for this to work.
#
Old snippet I know, but I have a fix for most field types (actually all of the ones I've tested including foreign keys and choice fields).
Replace Line 14:
Replace Line 48:
#