Index: django/newforms/widgets.py
===================================================================
--- django/newforms/widgets.py	(revision 4992)
+++ django/newforms/widgets.py	(working copy)
@@ -66,6 +66,18 @@
         return id_
     id_for_label = classmethod(id_for_label)
 
+class DisplayWidget(Widget):
+    """
+    Base class for all read-only pseudo-widgets. Those are used by the admin interface to display read-only values
+    """
+    def render(self, name, value, attrs=None):
+        if value is None: 
+            value = '[Null]'
+        if value == '':
+            value = '[Blank]'
+        return smart_unicode(value)
+    
+
 class Input(Widget):
     """
     Base class for all <input> widgets (except type='checkbox' and
Index: django/contrib/admin/options.py
===================================================================
--- django/contrib/admin/options.py	(revision 4992)
+++ django/contrib/admin/options.py	(working copy)
@@ -111,6 +111,8 @@
     fields = None
     raw_id_fields = ()
     prepopulated_fields = {}
+    # this list contains fields that will only be changed when adding an object. They'll only be displayed in change forms
+    readonly_fields = ()
     filter_vertical = ()
     filter_horizontal = ()
 
@@ -201,13 +203,25 @@
         for fs in self.fieldsets(request):
             yield fs
 
-    def formfield_for_dbfield(self, db_field, **kwargs):
+    def formfield_for_dbfield_add(self, db_field, override_readonly=True, **kwargs):
         """
+        call formfield_for_dbfield with override_readonly = True. Used for admin add object forms
+        """
+        return self.formfield_for_dbfield(db_field, override_readonly, **kwargs)
+        
+    def formfield_for_dbfield(self, db_field, override_readonly=False, **kwargs):
+        """
         Hook for specifying the form Field instance for a given database Field
         instance.
 
         If kwargs are given, they're passed to the form Field's constructor.
         """
+        # specify that this value cannot be edited by the user. The formfield will decide how to render this.
+        # The override is used by the create form to set the value. 
+        if not override_readonly and db_field.name in self.readonly_fields:
+            kwargs['widget'] = DisplayWidget
+#            kwargs['readonly'] = True
+            
         # For ManyToManyFields with a filter interface, use a special Widget.
         if isinstance(db_field, models.ManyToManyField) and db_field.name in (self.filter_vertical + self.filter_horizontal):
             kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
@@ -392,7 +406,7 @@
             # Object list will give 'Permission Denied', so go back to admin home
             post_url = '../../../'
 
-        ModelForm = forms.form_for_model(model, formfield_callback=self.formfield_for_dbfield)
+        ModelForm = forms.form_for_model(model, formfield_callback=self.formfield_for_dbfield_add)
 
         if request.POST:
             new_data = request.POST.copy()
@@ -443,6 +457,11 @@
             new_data = request.POST.copy()
             if opts.has_field_type(models.FileField):
                 new_data.update(request.FILES)
+            # get the values for readonly fields from the object, because they are displayed as strings instead of widgets and thus are not part of the POST request 
+            for fieldname in self.readonly_fields:
+                fieldvalue = getattr(obj, fieldname)
+                new_data[fieldname] = fieldvalue
+                
             form = ModelForm(new_data)
 
             if form.is_valid():
