diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index 0055e83..1a7fde7 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -4,6 +4,7 @@ from django.contrib.admin.util import (flatten_fieldsets, lookup_field,
     display_for_field, label_for_field, help_text_for_field)
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ObjectDoesNotExist
+from django.db import models
 from django.db.models.fields.related import ManyToManyRel
 from django.forms.util import flatatt
 from django.template.defaultfilters import capfirst
@@ -36,11 +37,13 @@ class AdminForm(object):
 
     def __iter__(self):
         for name, options in self.fieldsets:
-            yield Fieldset(self.form, name,
+            fieldset = Fieldset(self.form, name,
                 readonly_fields=self.readonly_fields,
                 model_admin=self.model_admin,
                 **options
             )
+            if not fieldset.hidden:
+                yield fieldset
 
     def first_field(self):
         try:
@@ -73,16 +76,25 @@ class Fieldset(object):
         self.model_admin = model_admin
         self.readonly_fields = readonly_fields
 
-    def _media(self):
+    @property
+    def media(self):
         if 'collapse' in self.classes:
             js = ['js/jquery.min.js', 'js/jquery.init.js', 'js/collapse.min.js']
             return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
         return forms.Media()
-    media = property(_media)
+
+    @property
+    def hidden(self):
+        # The fieldset is visible only if there is at least one visible line in it
+        for line in self:
+            return False
+        return True
 
     def __iter__(self):
         for field in self.fields:
-            yield Fieldline(self.form, field, self.readonly_fields, model_admin=self.model_admin)
+            line = Fieldline(self.form, field, self.readonly_fields, model_admin=self.model_admin)
+            if not line.hidden:
+                yield line
 
 class Fieldline(object):
     def __init__(self, form, field, readonly_fields=None, model_admin=None):
@@ -96,13 +108,22 @@ class Fieldline(object):
             readonly_fields = ()
         self.readonly_fields = readonly_fields
 
+    @property
+    def hidden(self):
+        # The line is visible only if there is at least one visible field in it
+        for field in self:
+            return False
+        return True
+
     def __iter__(self):
         for i, field in enumerate(self.fields):
             if field in self.readonly_fields:
-                yield AdminReadonlyField(self.form, field, is_first=(i == 0),
+                field_obj = AdminReadonlyField(self.form, field, is_first=(i == 0),
                     model_admin=self.model_admin)
             else:
-                yield AdminField(self.form, field, is_first=(i == 0))
+                field_obj = AdminField(self.form, field, is_first=(i == 0))
+            if not field_obj.hidden:
+                yield field_obj
 
     def errors(self):
         return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields if f not in self.readonly_fields]).strip('\n'))
@@ -112,6 +133,7 @@ class AdminField(object):
         self.field = form[field] # A django.forms.BoundField instance
         self.is_first = is_first # Whether this field is first on the line
         self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
+        self.hidden = False
 
     def label_tag(self):
         classes = []
@@ -138,8 +160,19 @@ class AdminReadonlyField(object):
         # For convenience, store other field-related data here too.
         if callable(field):
             class_name = field.__name__ != '<lambda>' and field.__name__ or ''
+            self.hidden = False
         else:
             class_name = field
+            if form.instance.pk is None:
+                # Creation form, field is hidden unless it has a default or isn't a real field
+                try:
+                    f = form.instance._meta.get_field(field)
+                except models.FieldDoesNotExist:
+                    self.hidden = False
+                else:
+                    self.hidden = f.default is models.fields.NOT_PROVIDED
+            else:
+                self.hidden = False
         self.field = {
             'name': class_name,
             'label': label,
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index b65f8a4..911c806 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -758,6 +758,33 @@ class OtherStoryAdmin(admin.ModelAdmin):
     list_display_links = ('title', 'id') # 'id' in list_display_links
     list_editable = ('content', )
 
+class ReadonlyFieldsetTestModel(models.Model):
+    field1 = models.CharField(max_length=100)
+    field2 = models.CharField(max_length=100)
+    field3 = models.CharField(max_length=100)
+    field4 = models.CharField(max_length=100)
+    field5 = models.CharField(max_length=100)
+    field6 = models.CharField(max_length=100)
+    field7 = models.CharField(max_length=100, default=lambda:'foo')
+    field8 = models.CharField(max_length=100, default='foo')
+
+class ReadonlyFieldsetTestAdmin(admin.ModelAdmin):
+    fieldsets = (
+        (None, {
+            'fields': ('field1', 'field2')
+        }),
+        ('Set1', {
+            'fields': ('field3', 'field4')
+        }),
+        ('Set2', {
+            'fields': ('field5', 'field6')
+        }),
+        ('Set3', {
+            'fields': ('field7', 'field8')
+        }),
+    )
+    readonly_fields = ('field4', 'field5', 'field6', 'field7', 'field8')
+
 admin.site.register(Article, ArticleAdmin)
 admin.site.register(CustomArticle, CustomArticleAdmin)
 admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@@ -800,6 +827,7 @@ admin.site.register(Paper, PaperAdmin)
 admin.site.register(CoverLetter, CoverLetterAdmin)
 admin.site.register(Story, StoryAdmin)
 admin.site.register(OtherStory, OtherStoryAdmin)
+admin.site.register(ReadonlyFieldsetTestModel, ReadonlyFieldsetTestAdmin)
 
 # 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 57bd87f..372ba33 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -36,7 +36,8 @@ from models import (Article, BarAccount, CustomArticle, EmptyModel,
     Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
     Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
     Question, Answer, Inquisition, Actor, FoodDelivery,
-    RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory)
+    RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory, 
+    ReadonlyFieldsetTestModel)
 
 
 class AdminViewBasicTest(TestCase):
@@ -2619,6 +2620,34 @@ class ReadonlyTest(TestCase):
         response = self.client.get('/test_admin/admin/admin_views/post/%d/' % p.pk)
         self.assertContains(response, "%d amount of cool" % p.pk)
 
+        response = self.client.get('/test_admin/admin/admin_views/readonlyfieldsettestmodel/add/')
+        self.assertContains(response, 'Field1:</label>')
+        self.assertContains(response, 'Field2:</label>')
+        self.assertContains(response, 'Set1')
+        self.assertContains(response, 'Field3:</label>')
+        self.assertNotContains(response, 'Field4:</label>')
+        self.assertNotContains(response, 'Set2')
+        self.assertNotContains(response, 'Field5:</label>')
+        self.assertNotContains(response, 'Field6:</label>')
+        self.assertContains(response, 'Set3')
+        self.assertContains(response, 'Field7:</label>')
+        self.assertContains(response, 'Field8:</label>')
+
+        obj = ReadonlyFieldsetTestModel.objects.create(field1='a', field2='b', field3='c',
+                                                       field4='d', field5='e', field6='f')
+        response = self.client.get('/test_admin/admin/admin_views/readonlyfieldsettestmodel/%d/' % obj.pk)
+        self.assertContains(response, 'Field1:</label>')
+        self.assertContains(response, 'Field2:</label>')
+        self.assertContains(response, 'Set1')
+        self.assertContains(response, 'Field3:</label>')
+        self.assertContains(response, 'Field4:</label>')
+        self.assertContains(response, 'Set2')
+        self.assertContains(response, 'Field5:</label>')
+        self.assertContains(response, 'Field6:</label>')
+        self.assertContains(response, 'Set3')
+        self.assertContains(response, 'Field7:</label>')
+        self.assertContains(response, 'Field8:</label>')
+
     def test_readonly_post(self):
         data = {
             "title": "Django Got Readonly Fields",
