Reputation: 416
I want to display a field as read only in a ModelAdmin
form, so I added it to the readonly_fields
attribute.
However, since the field contains a currency, stored as an integer, I want to apply some nice formatting it. I've created a custom ModelForm
for my ModelAdmin
, trying to apply the formatting in the overridden __init__
method.
The problem is, I cannot find the value. The field is not present in the self.fields
attribute.
Does anyone know where the values for the readonly_fields
are kept, or is there a better/different approach?
Upvotes: 2
Views: 1887
Reputation: 1840
Another, more appropriate solution, works in Django 2.1.2:
ModelAdmin renders read-only fields via special wrapper AdminReadonlyField (django/contrib/admin/helpers.py) if we look at contents
method, we can see
the code
if getattr(widget, 'read_only', False):
return widget.render(field, value)
It means that if a widget has read_only
attribute with True
value
then the read-only field will invoke widget's render method.
Hence, you can use render method to format your value.
For example:
class CustomDateInput(widgets.DateInput):
read_only = True
def _render(self, template_name, context, renderer=None):
return 'you value'
class CustomForm(forms.ModelForm):
some_field = forms.DateTimeField(widget=CustomDateInput())
@admin.register(SomeModel)
class SomeModelAdmin(admin.ModelAdmin):
form = CustomForm
readonly_fields = ['some_field']
Upvotes: 3
Reputation: 174698
An alternate approach, which works for all types of forms is to create a widget to represent a read only field. Here is one that I wrote for my own use. You can change the <span %s>%s</span>
to suit your own requirements.
from django import forms
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
class ReadOnlyWidget(forms.TextInput):
def render(self, name, value, attrs=None):
if value is None:
value = ''
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
if value != '':
# Only add the 'value' attribute if a value is non-empty.
final_attrs['value'] = force_unicode(self._format_value(value))
return mark_safe(u'<span%s />%s</span>' % (flatatt(final_attrs),value))
Once you have that added, simply do this:
class MyAdmin(admin.ModelAdmin):
foo = models.TextField(widget=ReadOnlyWidget(attrs={'class':'read-only'}
initial="$50")
Then in your CSS, do some styling for a read-only
class, or you can adjust the attributes accordingly.
Upvotes: 4
Reputation: 118518
Just do something like:
class MyAdmin(admin.ModelAdmin):
readonly_fields = ('foo',)
def foo(self, obj):
return '${0}'.format(obj.amount)
Upvotes: 3