diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index 806be24..133e0fc 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -186,7 +186,7 @@ def items_for_result(cl, result, form):
             # By default the fields come from ModelAdmin.list_editable, but if we pull
             # the fields out of the form instead of list_editable custom admins
             # can provide fields on a per request basis
-            if form and field_name in form.fields:
+            if form and field_name in form.fields and not form[field_name].is_hidden:
                 bf = form[field_name]
                 result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf))
             else:
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 60319ea..1890674 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -669,6 +669,24 @@ class Answer(models.Model):
 class Reservation(models.Model):
     start_date = models.DateTimeField()
     price = models.IntegerField()
+
+class Story(models.Model):
+    title = models.CharField(max_length=100)
+    content = models.TextField()
+    
+class StoryAdmin(admin.ModelAdmin):
+    list_display = ('id', 'title', 'content')
+    list_display_links = ('title',) # 'id' not in list_display_links
+    list_editable = ('content', )
+
+class OtherStory(models.Model):
+    title = models.CharField(max_length=100)
+    content = models.TextField()
+    
+class OtherStoryAdmin(admin.ModelAdmin):
+    list_display = ('id', 'title', 'content')
+    list_display_links = ('title', 'id') # 'id' in list_display_links
+    list_editable = ('content', )
     
 admin.site.register(Article, ArticleAdmin)
 admin.site.register(CustomArticle, CustomArticleAdmin)
@@ -706,6 +724,8 @@ admin.site.register(CyclicOne)
 admin.site.register(CyclicTwo)
 admin.site.register(WorkHour, WorkHourAdmin)
 admin.site.register(Reservation)
+admin.site.register(Story, StoryAdmin)
+admin.site.register(OtherStory, OtherStoryAdmin)
 
 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
 # That way we cover all four cases:
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index acbbbfc..b3c691a 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -35,7 +35,7 @@ from models import (Article, BarAccount, CustomArticle, EmptyModel,
     Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
     Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
     Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
-    Question, Answer, Inquisition, Actor)
+    Question, Answer, Inquisition, Actor, Story, OtherStory)
 
 
 class AdminViewBasicTest(TestCase):
@@ -1563,7 +1563,34 @@ class AdminViewListEditable(TestCase):
         response = self.client.get('/test_admin/admin/admin_views/person/?%s' % IS_POPUP_VAR)
         self.assertEqual(response.context['cl'].list_editable, ())
 
-
+    def test_hidden_fields(self):
+        """ Ensure that hidden fields aren't displayed in the table body and
+            that their corresponding human-readable value is displayed instead.
+            Note that hidden fields should in fact be displayed but separately 
+            (not in the table) and only once.
+            Refs #12475.
+        """
+        Story.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...')
+        Story.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...')
+        response = self.client.get('/test_admin/admin/admin_views/story/')
+        self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
+        self.assertContains(response, 'id="id_form-1-id"', 1)
+        self.assertContains(response, '<td>1</td>', 1)
+        self.assertContains(response, '<td>2</td>', 1)
+
+    def test_hidden_fields_with_list_display_links(self):
+        """ Similarly as test_hidden_fields, but when the hidden fields are
+            referenced in list_display_links.
+            Refs #12475.
+        """
+        OtherStory.objects.create(title='The adventures of Guido', content='Once upon a time in Djangoland...')
+        OtherStory.objects.create(title='Crouching Tiger, Hidden Python', content='The Python was sneaking into...')
+        response = self.client.get('/test_admin/admin/admin_views/otherstory/')
+        self.assertContains(response, 'id="id_form-0-id"', 1) # Only one hidden field, in a separate place than the table.
+        self.assertContains(response, 'id="id_form-1-id"', 1)
+        self.assertContains(response, '<th><a href="1/">1</a></th>', 1)
+        self.assertContains(response, '<th><a href="2/">2</a></th>', 1)
+        
 class AdminSearchTest(TestCase):
     fixtures = ['admin-views-users','multiple-child-classes']
 
