diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index ed41c7f..bfd0f19 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -12,6 +12,7 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render_to_response
 from django.utils.functional import update_wrapper
 from django.utils.html import escape
+from django.utils.http import urlquote
 from django.utils.safestring import mark_safe
 from django.utils.functional import curry
 from django.utils.text import capfirst, get_text_list
@@ -26,6 +27,10 @@ HORIZONTAL, VERTICAL = 1, 2
 # returns the <ul> class for a given radio_admin field
 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '')
 
+# GET parameter for the URL to return to after change/add views. This lets the 
+# admin save the state of the changelist page through the change/add page.
+RETURN_GET_PARAM = 'return_to'
+
 class IncorrectLookupParameters(Exception):
     pass
 
@@ -452,31 +457,45 @@ class ModelAdmin(BaseModelAdmin):
         pk_value = obj._get_pk_val()
         
         msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
-        # Here, we distinguish between different save types by checking for
+        
+        # Below, we distinguish between different save types by checking for
         # the presence of keys in request.POST.
+        
+        # The user clicked "save and continue editing". Redirect to admin URL
+        # for this object, possibly in popup mode if needed.
         if request.POST.has_key("_continue"):
             self.message_user(request, msg + ' ' + _("You may edit it again below."))
             if request.POST.has_key("_popup"):
                 post_url_continue += "?_popup=1"
             return HttpResponseRedirect(post_url_continue % pk_value)
         
+        # This was a popup and the user clicked the simple "save" button.
+        # Return a little script which populates the calling page with the
+        # saved key.
         if request.POST.has_key("_popup"):
             return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
                 # escape() calls force_unicode.
                 (escape(pk_value), escape(obj)))
+        
+        # The user clicked "save and add another", so redirect back to the bare
+        # "add" page, which will be request.path.
         elif request.POST.has_key("_addanother"):
             self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
             return HttpResponseRedirect(request.path)
+        
+        # Just a regular "save" click. IF we've been pased an explicit return 
+        # URL in GET, go there. Otherwise, redirect to the plain changelist.
+        # If the user doesn't have changelist permission, just redirect back
+        # to the main admin index.
         else:
             self.message_user(request, msg)
-            
-            # Figure out where to redirect. If the user has change permission,
-            # redirect to the change-list page for this object. Otherwise,
-            # redirect to the admin index.
-            if self.has_change_permission(request, None):
+            if RETURN_GET_PARAM in request.GET:
+                post_url = request.GET[RETURN_GET_PARAM]
+            elif self.has_change_permission(request, None):
                 post_url = '../'
             else:
                 post_url = '../../../'
+
             return HttpResponseRedirect(post_url)
     
     def response_change(self, request, obj):
@@ -487,25 +506,38 @@ class ModelAdmin(BaseModelAdmin):
         pk_value = obj._get_pk_val()
         
         msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
+        
+        # Similar redirecting logic to response_add, above.
+        
+        # "Save and continue editing"
         if request.POST.has_key("_continue"):
             self.message_user(request, msg + ' ' + _("You may edit it again below."))
             if request.REQUEST.has_key('_popup'):
                 return HttpResponseRedirect(request.path + "?_popup=1")
             else:
                 return HttpResponseRedirect(request.path)
+        
+        # "Save as a new object"
         elif request.POST.has_key("_saveasnew"):
             msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': obj}
             self.message_user(request, msg)
             return HttpResponseRedirect("../%s/" % pk_value)
+        
+        # "Save and add another"
         elif request.POST.has_key("_addanother"):
             self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
             return HttpResponseRedirect("../add/")
+            
+        # "Save"
         else:
             self.message_user(request, msg)
-            return HttpResponseRedirect("../")
-    
+            post_url = request.GET.get(RETURN_GET_PARAM, '../')
+            return HttpResponseRedirect(post_url)
+
     def add_view(self, request, form_url='', extra_context=None):
-        "The 'add' admin view for this model."
+        """
+        The 'add' admin view for this model.
+        """
         model = self.model
         opts = model._meta
         
@@ -515,6 +547,8 @@ class ModelAdmin(BaseModelAdmin):
         ModelForm = self.get_form(request)
         formsets = []
         if request.method == 'POST':
+            return_to = request.GET.get(RETURN_GET_PARAM, None)
+
             form = ModelForm(request.POST, request.FILES)
             if form.is_valid():
                 form_validated = True
@@ -550,7 +584,12 @@ class ModelAdmin(BaseModelAdmin):
             for FormSet in self.get_formsets(request):
                 formset = FormSet(instance=self.model())
                 formsets.append(formset)
-        
+
+            return_to = request.META.get('HTTP_REFERER', None)
+
+        if return_to:
+            form_url = form_url + '?%s=%s' % (RETURN_GET_PARAM, urlquote(return_to))
+
         adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), self.prepopulated_fields)
         media = self.media + adminForm.media
         
@@ -573,7 +612,7 @@ class ModelAdmin(BaseModelAdmin):
             'app_label': opts.app_label,
         }
         context.update(extra_context or {})
-        return self.render_change_form(request, context, add=True)
+        return self.render_change_form(request, context, form_url=form_url, add=True)
     add_view = transaction.commit_on_success(add_view)
     
     def change_view(self, request, object_id, extra_context=None):
@@ -601,6 +640,8 @@ class ModelAdmin(BaseModelAdmin):
         ModelForm = self.get_form(request, obj)
         formsets = []
         if request.method == 'POST':
+            return_to = request.GET.get(RETURN_GET_PARAM, None)
+
             form = ModelForm(request.POST, request.FILES, instance=obj)
             if form.is_valid():
                 form_validated = True
@@ -628,7 +669,14 @@ class ModelAdmin(BaseModelAdmin):
             for FormSet in self.get_formsets(request, obj):
                 formset = FormSet(instance=obj)
                 formsets.append(formset)
-        
+
+            return_to = request.META.get('HTTP_REFERER', None)
+
+        if return_to:
+            form_url = '?%s=%s' % (RETURN_GET_PARAM, urlquote(return_to))
+        else:
+            form_url = ''
+
         adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields)
         media = self.media + adminForm.media
         
@@ -652,7 +700,7 @@ class ModelAdmin(BaseModelAdmin):
             'app_label': opts.app_label,
         }
         context.update(extra_context or {})
-        return self.render_change_form(request, context, change=True, obj=obj)
+        return self.render_change_form(request, context, change=True, form_url=form_url, obj=obj)
     change_view = transaction.commit_on_success(change_view)
     
     def changelist_view(self, request, extra_context=None):
