Django foreign keys only
I have two models, one is Employee and the other is Asset, with a Many-to-One relationship between Asset and Employee. And the Asset is added as a StackedInline field to the Employee admin interface, I can still make the Asset as a read-only field in Employee Admin.
My intention was to show all the assets that the employee currently holds in Admin so that he doesn't accidentally delete it.
Edit: Actually, I don't think this will work for inline models.
Django will be adding its own read-only fields in Django 1.1, due out around mid-March.
read-only fields ( http://www.djangosnippets.org/snippets/937/ )
This snippet will allow you to set fields as read-only in admin.
use this code and import it into admin.py as ReadonlyAdmin.This is a modified form of readonly admin.
from django import forms
from django.utils.safestring import mark_safe
from datetime import datetime
class ReadOnlyWidget(forms.Widget):
def __init__(self, original_value, display_value):
self.original_value = original_value
self.display_value = display_value
super(ReadOnlyWidget, self).__init__()
def render(self, name, value, attrs=None):
if self.display_value is not None:
return unicode(self.display_value)
return unicode(self.original_value)
def value_from_datadict(self, data, files, name):
return self.original_value
#to make fields foreignkey readonly
class ReadOnlyAdminFields(object):
def get_form(self, request, obj=None):
form = super(ReadOnlyAdminFields, self).get_form(request, obj)
if hasattr(self, 'readonly') and obj is not None:
for field_name in self.readonly:
if field_name in form.base_fields:
if hasattr(obj, 'get_%s_display' % field_name):
display_value = getattr(obj, 'get_%s_display' % field_name)()
else:
display_value = None
if getattr(obj, field_name).__class__ in [unicode , long, int, float, datetime, list]:
form.base_fields[field_name].widget = ReadOnlyWidget(getattr(obj, field_name), display_value)
else:
form.base_fields[field_name].widget = ReadOnlyWidget(getattr(obj, field_name).id, display_value)
form.base_fields[field_name].required = False
return form
I don't think there is a flag in django-admin for this, check out chapter 18 of the Django book for more details, you need to hack the templates manually
http://www.djangobook.com/en/beta/chapter18/
I think that perhaps you can add a custom widget to fields that have only a basic form, other than being "disabled" for all elements. I cannot tell you how to remove the ability to add new entries.
If you only want to display employee assets, you can change the default django admin change_form.html. (and you can also disable inline first)
To override the default admin templates, copy the admin template folder to your local django templates folder ($ {TEMPLATE_DIRS} in your settings.py file)
And there is this block in the change_form.html file,
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
Used to display inline strings, and here you can do some additional information like a list of assets of the current employee and place them above where the inline strings originate from.
And now the question is, how do I provide this additional information to this template? This can be done by overriding the change_view () function in your Employee admin model.
For example in your admin.py
class EmployeeAdmin(admin.ModelAdmin):
...
def change_view(self, request, object_id, extra_context=None):
assets = Asset.objects.filter(employee=Employee.objects.get(id=object_id))
context_data = {'inlines': assets, }
return super(EmployeeAdmin, self).change_view(request, object_id, extra_context=context_data)
Now go back to your admin change_form.html, user template tags to display the extra_context from your EmployeeAdmin.
eg,
{% for inline in inlines %}
{{ inline }}
{% endfor %}
{% for inline_admin_formset in inline_admin_formsets %}
{% include inline_admin_formset.opts.template %}
{% endfor %}
Hope it helps and this is as of django 1.2.4