app/django/contrib/admin/templatetags/admin_list.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
--- a/app/django/contrib/admin/templatetags/admin_list.py	Tue Oct 14 12:36:55 2008 +0000
+++ b/app/django/contrib/admin/templatetags/admin_list.py	Tue Oct 14 16:00:59 2008 +0000
@@ -70,8 +70,9 @@
 
 def result_headers(cl):
     lookup_opts = cl.lookup_opts
-
-    for i, field_name in enumerate(lookup_opts.admin.list_display):
+    
+    for i, field_name in enumerate(cl.list_display):
+        attr = None
         try:
             f = lookup_opts.get_field(field_name)
             admin_order_field = None
@@ -84,14 +85,30 @@
             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
@@ -99,11 +116,7 @@
             # So this _is_ a sortable non-field.  Go to the yield
             # after the else clause.
         else:
-            if isinstance(f.rel, models.ManyToOneRel) and f.null:
-                yield {"text": f.verbose_name}
-                continue
-            else:
-                header = f.verbose_name
+            header = f.verbose_name
 
         th_classes = []
         new_order_type = 'asc'
@@ -123,24 +136,34 @@
 def items_for_result(cl, result):
     first = True
     pk = cl.lookup_opts.pk.attname
-    for field_name in cl.lookup_opts.admin.list_display:
+    for field_name in cl.list_display:
         row_class = ''
         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) and \
+                   not field_name == '__str__' and not field_name == '__unicode__':
+                    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:
@@ -189,13 +212,17 @@
         if force_unicode(result_repr) == '':
             result_repr = mark_safe(' ')
         # If list_display_links not defined, add the link tag to the first field
-        if (first and not cl.lookup_opts.admin.list_display_links) or field_name in cl.lookup_opts.admin.list_display_links:
+        if (first and not cl.list_display_links) or field_name in cl.list_display_links:
             table_tag = {True:'th', False:'td'}[first]
             first = False
             url = cl.url_for_result(result)
             # Convert the pk to something that can be used in Javascript.
             # Problem cases are long ints (23L) and non-ASCII strings.
-            result_id = repr(force_unicode(getattr(result, pk)))[1:]
+            if cl.to_field:
+                attr = str(cl.to_field)
+            else:
+                attr = pk
+            result_id = repr(force_unicode(getattr(result, attr)))[1:]
             yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
                 (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
         else:
@@ -212,8 +239,8 @@
 result_list = register.inclusion_tag("admin/change_list_results.html")(result_list)
 
 def date_hierarchy(cl):
-    if cl.lookup_opts.admin.date_hierarchy:
-        field_name = cl.lookup_opts.admin.date_hierarchy
+    if cl.date_hierarchy:
+        field_name = cl.date_hierarchy
         year_field = '%s__year' % field_name
         month_field = '%s__month' % field_name
         day_field = '%s__day' % field_name
@@ -275,15 +302,11 @@
 def search_form(cl):
     return {
         'cl': cl,
-        'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field,
+        'show_result_count': cl.result_count != cl.full_result_count,
         'search_var': SEARCH_VAR
     }
 search_form = register.inclusion_tag('admin/search_form.html')(search_form)
 
-def filter(cl, spec):
+def admin_list_filter(cl, spec):
     return {'title': spec.title(), 'choices' : list(spec.choices(cl))}
-filter = register.inclusion_tag('admin/filter.html')(filter)
-
-def filters(cl):
-    return {'cl': cl}
-filters = register.inclusion_tag('admin/filters.html')(filters)
+admin_list_filter = register.inclusion_tag('admin/filter.html')(admin_list_filter)