summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorBrian Rosner <brosner@gmail.com>2008-08-14 20:12:19 +0000
committerBrian Rosner <brosner@gmail.com>2008-08-14 20:12:19 +0000
commitb2ec6473c09bcad88194cfb52252c44ed7e960aa (patch)
treeee849bf6c234dfaa810bfb5f47ba4356c0aaa54a /django
parent9e423b51e325c9226e2f744bfa52336a626bf63a (diff)
Fixed #7503 -- Allow callables in list_display. This also does a lookup on the ModelAdmin for the method if the value is a string before looking on the model. Refs #8054. Thanks qmanic and Daniel Pope for tickets and patches.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8352 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/contrib/admin/templatetags/admin_list.py45
-rw-r--r--django/contrib/admin/validation.py19
2 files changed, 49 insertions, 15 deletions
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 87fad70ec3..c837cbe72a 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -84,14 +84,30 @@ def result_headers(cl):
elif field_name == '__str__':
header = smart_str(lookup_opts.verbose_name)
else:
- attr = getattr(cl.model, field_name) # Let AttributeErrors propagate.
+ if callable(field_name):
+ attr = field_name # field_name can be a callable
+ else:
+ try:
+ attr = getattr(cl.model_admin, field_name)
+ except AttributeError:
+ try:
+ attr = getattr(cl.model, field_name)
+ except AttributeError:
+ raise AttributeError, \
+ "'%s' model or '%s' objects have no attribute '%s'" % \
+ (lookup_opts.object_name, cl.model_admin.__class__, field_name)
+
try:
header = attr.short_description
except AttributeError:
- header = field_name.replace('_', ' ')
+ if callable(field_name):
+ header = field_name.__name__
+ else:
+ header = field_name
+ header = header.replace('_', ' ')
# It is a non-field, but perhaps one that is sortable
- admin_order_field = getattr(getattr(cl.model, field_name), "admin_order_field", None)
+ admin_order_field = getattr(attr, "admin_order_field", None)
if not admin_order_field:
yield {"text": header}
continue
@@ -128,19 +144,28 @@ def items_for_result(cl, result):
try:
f = cl.lookup_opts.get_field(field_name)
except models.FieldDoesNotExist:
- # For non-field list_display values, the value is either a method
- # or a property.
+ # For non-field list_display values, the value is either a method,
+ # property or returned via a callable.
try:
- attr = getattr(result, field_name)
+ if callable(field_name):
+ attr = field_name
+ value = attr(result)
+ elif hasattr(cl.model_admin, field_name):
+ attr = getattr(cl.model_admin, field_name)
+ value = attr(result)
+ else:
+ attr = getattr(result, field_name)
+ if callable(attr):
+ value = attr()
+ else:
+ value = attr
allow_tags = getattr(attr, 'allow_tags', False)
boolean = getattr(attr, 'boolean', False)
- if callable(attr):
- attr = attr()
if boolean:
allow_tags = True
- result_repr = _boolean_icon(attr)
+ result_repr = _boolean_icon(value)
else:
- result_repr = smart_unicode(attr)
+ result_repr = smart_unicode(value)
except (AttributeError, ObjectDoesNotExist):
result_repr = EMPTY_CHANGELIST_VALUE
else:
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
index a42f2eb985..48e35c68b3 100644
--- a/django/contrib/admin/validation.py
+++ b/django/contrib/admin/validation.py
@@ -35,11 +35,20 @@ def validate(cls, model):
if hasattr(cls, 'list_display'):
_check_istuplew('list_display', cls.list_display)
for idx, field in enumerate(cls.list_display):
- f = _check_attr_existsw("list_display[%d]" % idx, field)
- if isinstance(f, models.ManyToManyField):
- raise ImproperlyConfigured("`%s.list_display[%d]`, `%s` is a "
- "ManyToManyField which is not supported."
- % (cls.__name__, idx, field))
+ if not callable(field):
+ if not hasattr(cls, field):
+ if not hasattr(model, field):
+ try:
+ return opts.get_field(field)
+ except models.FieldDoesNotExist:
+ raise ImproperlyConfigured("%s.list_display[%d], %r is "
+ "not a callable or an attribute of %r or found in the model %r."
+ % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))
+ f = _check_attr_existsw("list_display[%d]" % idx, field)
+ if isinstance(f, models.ManyToManyField):
+ raise ImproperlyConfigured("`%s.list_display[%d]`, `%s` is a "
+ "ManyToManyField which is not supported."
+ % (cls.__name__, idx, field))
# list_display_links
if hasattr(cls, 'list_display_links'):