Index: django/contrib/admin/templatetags/admin_list.py
===================================================================
--- django/contrib/admin/templatetags/admin_list.py	(revision 9032)
+++ django/contrib/admin/templatetags/admin_list.py	(working copy)
@@ -73,8 +73,9 @@
     
     for i, field_name in enumerate(cl.list_display):
         attr = None
+        nested_name = field_name.split('__')
         try:
-            f = lookup_opts.get_field(field_name)
+            f = lookup_opts.get_field(nested_name[0])
             admin_order_field = None
         except models.FieldDoesNotExist:
             # For non-field list_display values, check for the function
@@ -142,8 +143,9 @@
     pk = cl.lookup_opts.pk.attname
     for field_name in cl.list_display:
         row_class = ''
+        nested_name = field_name.split('__')
         try:
-            f = cl.lookup_opts.get_field(field_name)
+            f = cl.lookup_opts.get_field(nested_name[0])
         except models.FieldDoesNotExist:
             # For non-field list_display values, the value is either a method,
             # property or returned via a callable.
@@ -179,40 +181,7 @@
                     result_repr = mark_safe(result_repr)
         else:
             field_val = getattr(result, f.attname)
-
-            if isinstance(f.rel, models.ManyToOneRel):
-                if field_val is not None:
-                    result_repr = escape(getattr(result, f.name))
-                else:
-                    result_repr = EMPTY_CHANGELIST_VALUE
-            # Dates and times are special: They're formatted in a certain way.
-            elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):
-                if field_val:
-                    (date_format, datetime_format, time_format) = get_date_formats()
-                    if isinstance(f, models.DateTimeField):
-                        result_repr = capfirst(dateformat.format(field_val, datetime_format))
-                    elif isinstance(f, models.TimeField):
-                        result_repr = capfirst(dateformat.time_format(field_val, time_format))
-                    else:
-                        result_repr = capfirst(dateformat.format(field_val, date_format))
-                else:
-                    result_repr = EMPTY_CHANGELIST_VALUE
-                row_class = ' class="nowrap"'
-            # Booleans are special: We use images.
-            elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
-                result_repr = _boolean_icon(field_val)
-            # DecimalFields are special: Zero-pad the decimals.
-            elif isinstance(f, models.DecimalField):
-                if field_val is not None:
-                    result_repr = ('%%.%sf' % f.decimal_places) % field_val
-                else:
-                    result_repr = EMPTY_CHANGELIST_VALUE
-            # Fields with choices are special: Use the representation
-            # of the choice.
-            elif f.choices:
-                result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
-            else:
-                result_repr = escape(field_val)
+            result_repr = field_item(cl, result, nested_name, f)
         if force_unicode(result_repr) == '':
             result_repr = mark_safe('&nbsp;')
         # If list_display_links not defined, add the link tag to the first field
@@ -232,6 +201,49 @@
         else:
             yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr)))
 
+def field_item(cl, result, nested_name, f):
+    field_val = getattr(result, f.attname)
+
+    if isinstance(f.rel, models.ManyToOneRel):
+        if field_val is not None:
+            val = getattr(result, f.name)
+            if len(nested_name) == 1:
+                result_repr = escape(val)
+            else:
+                f = val._meta.get_field(nested_name[1])
+                result_repr = field_item(cl, val, nested_name[1:], f)
+        else:
+            result_repr = EMPTY_CHANGELIST_VALUE
+    # Dates and times are special: They're formatted in a certain way.
+    elif isinstance(f, models.DateField) or isinstance(f, models.TimeField):
+        if field_val:
+            (date_format, datetime_format, time_format) = get_date_formats()
+            if isinstance(f, models.DateTimeField):
+                result_repr = capfirst(dateformat.format(field_val, datetime_format))
+            elif isinstance(f, models.TimeField):
+                result_repr = capfirst(dateformat.time_format(field_val, time_format))
+            else:
+                result_repr = capfirst(dateformat.format(field_val, date_format))
+        else:
+            result_repr = EMPTY_CHANGELIST_VALUE
+        row_class = ' class="nowrap"'
+    # Booleans are special: We use images.
+    elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
+        result_repr = _boolean_icon(field_val)
+    # DecimalFields are special: Zero-pad the decimals.
+    elif isinstance(f, models.DecimalField):
+        if field_val is not None:
+            result_repr = ('%%.%sf' % f.decimal_places) % field_val
+        else:
+            result_repr = EMPTY_CHANGELIST_VALUE
+            # Fields with choices are special: Use the representation
+            # of the choice.
+    elif f.choices:
+        result_repr = dict(f.choices).get(field_val, EMPTY_CHANGELIST_VALUE)
+    else:
+        result_repr = escape(field_val)
+    return result_repr
+
 def results(cl):
     for res in cl.result_list:
         yield list(items_for_result(cl,res))
Index: tests/regressiontests/admin_views/tests.py
===================================================================
--- tests/regressiontests/admin_views/tests.py	(revision 9032)
+++ tests/regressiontests/admin_views/tests.py	(working copy)
@@ -99,6 +99,11 @@
         response = self.client.post('/test_admin/admin/admin_views/section/1/', post_data)
         self.failUnlessEqual(response.status_code, 302) # redirect somewhere
 
+    def testNestedListDisplay(self):
+        response = self.client.get('/test_admin/admin/admin_views/article/')
+        self.failUnlessEqual(response.status_code, 200)
+        self.assertContains(response, 'Test section')
+
 def get_perm(Model, perm):
     """Return the permission object, for the Model"""
     ct = ContentType.objects.get_for_model(Model)
Index: tests/regressiontests/admin_views/models.py
===================================================================
--- tests/regressiontests/admin_views/models.py	(revision 9032)
+++ tests/regressiontests/admin_views/models.py	(working copy)
@@ -24,7 +24,7 @@
     model = Article
 
 class ArticleAdmin(admin.ModelAdmin):
-    list_display = ('content', 'date')
+    list_display = ('content', 'date', 'section__name')
     list_filter = ('date',)
 
     def changelist_view(self, request):
