Index: django/django/contrib/admin/options.py
===================================================================
--- django/django/contrib/admin/options.py	(revision 8128)
+++ django/django/contrib/admin/options.py	(working copy)
@@ -325,7 +325,7 @@
         for inline in self.inline_instances:
             yield inline.get_formset(request, obj)
 
-    def save_add(self, request, form, formsets, post_url_continue):
+    def save_add(self, request, form, formsets, post_url_continue, post_url_has_change_permission='../', post_url_has_not_change_permission='../../../'):
         """
         Saves the object in the "add" stage and returns an HttpResponseRedirect.
 
@@ -366,13 +366,12 @@
             # redirect to the change-list page for this object. Otherwise,
             # redirect to the admin index.
             if self.has_change_permission(request, None):
-                post_url = '../'
+                return HttpResponseRedirect(post_url_has_change_permission)
             else:
-                post_url = '../../../'
-            return HttpResponseRedirect(post_url)
+                return HttpResponseRedirect(post_url_has_not_change_permission)
     save_add = transaction.commit_on_success(save_add)
 
-    def save_change(self, request, form, formsets=None):
+    def save_change(self, request, form, formsets=None, post_url_save_as_new="../%s/", post_url_add_another="../add/", post_url_save="../"):
         """
         Saves the object in the "change" stage and returns an HttpResponseRedirect.
 
@@ -423,13 +422,13 @@
                 return HttpResponseRedirect(request.path)
         elif request.POST.has_key("_saveasnew"):
             request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
-            return HttpResponseRedirect("../%s/" % pk_value)
+            return HttpResponseRedirect(post_url_save_as_new % pk_value)
         elif request.POST.has_key("_addanother"):
             request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
-            return HttpResponseRedirect("../add/")
+            return HttpResponseRedirect(post_url_add_another)
         else:
             request.user.message_set.create(message=msg)
-            return HttpResponseRedirect("../")
+            return HttpResponseRedirect(post_url_save)
     save_change = transaction.commit_on_success(save_change)
 
     def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
@@ -458,7 +457,7 @@
             "admin/change_form.html"
         ], context, context_instance=template.RequestContext(request))
 
-    def add_view(self, request, form_url='', extra_context=None):
+    def add_view(self, request, form_url='', extra_context=None, post_url_continue='../%s/'):
         "The 'add' admin view for this model."
         model = self.model
         opts = model._meta
@@ -484,7 +483,7 @@
                     instance=obj, save_as_new=request.POST.has_key("_saveasnew"))
                 inline_formsets.append(inline_formset)
             if all_valid(inline_formsets) and form.is_valid():
-                return self.save_add(request, form, inline_formsets, '../%s/')
+                return self.save_add(request, form, inline_formsets, post_url_continue)
         else:
             form = ModelForm(initial=dict(request.GET.items()))
             for FormSet in self.get_formsets(request):
@@ -515,7 +514,7 @@
         context.update(extra_context or {})
         return self.render_change_form(request, context, add=True)
 
-    def change_view(self, request, object_id, extra_context=None):
+    def change_view(self, request, object_id, extra_context=None, form_url='../../add/'):
         "The 'change' admin view for this model."
         model = self.model
         opts = model._meta
@@ -536,7 +535,7 @@
             raise Http404('%s object with primary key %r does not exist.' % (opts.verbose_name, escape(object_id)))
 
         if request.POST and request.POST.has_key("_saveasnew"):
-            return self.add_view(request, form_url='../../add/')
+            return self.add_view(request, form_url)
 
         ModelForm = self.get_form(request, obj)
         inline_formsets = []
@@ -612,7 +611,7 @@
             'admin/change_list.html'
         ], context, context_instance=template.RequestContext(request))
 
-    def delete_view(self, request, object_id, extra_context=None):
+    def delete_view(self, request, object_id, extra_context=None, object_url="../../%s/", post_url_has_not_change_permission="../../../../", post_url_has_change_permission="../../"):
         "The 'delete' admin view for this model."
         from django.contrib.admin.models import LogEntry, DELETION
         opts = self.model._meta
@@ -634,7 +633,8 @@
 
         # Populate deleted_objects, a data structure of all related objects that
         # will also be deleted.
-        deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), quote(object_id), escape(obj))), []]
+        object_rendered_url = object_url % quote(object_id)
+        deleted_objects = [mark_safe(u'%s: <a href="%s">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), object_rendered_url, escape(obj))), []]
         perms_needed = sets.Set()
         get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1, self.admin_site)
 
@@ -646,8 +646,8 @@
             LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(self.model).id, object_id, obj_display, DELETION)
             request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})
             if not self.has_change_permission(request, None):
-                return HttpResponseRedirect("../../../../")
-            return HttpResponseRedirect("../../")
+                return HttpResponseRedirect(post_url_has_not_change_permission)
+            return HttpResponseRedirect(post_url_has_change_permission)
         
         context = {
             "title": _("Are you sure?"),
