diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 5271e02..2825c99 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -11,6 +11,7 @@ from django.contrib import messages
 from django.views.decorators.csrf import csrf_protect
 from django.core.exceptions import PermissionDenied, ValidationError
 from django.core.paginator import Paginator
+from django.core.urlresolvers import reverse
 from django.db import models, transaction, router
 from django.db.models.related import RelatedObject
 from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
@@ -776,9 +777,12 @@ class ModelAdmin(BaseModelAdmin):
             # redirect to the change-list page for this object. Otherwise,
             # redirect to the admin index.
             if self.has_change_permission(request, None):
-                post_url = '../'
+                post_url = reverse('admin:%s_%s_changelist' %
+                                   (opts.app_label, opts.module_name),
+                                   current_app=self.admin_site.name)
             else:
-                post_url = '../../../'
+                post_url = reverse('admin:index',
+                                   current_app=self.admin_site.name)
             return HttpResponseRedirect(post_url)
 
     def response_change(self, request, obj):
@@ -787,11 +791,14 @@ class ModelAdmin(BaseModelAdmin):
         """
         opts = obj._meta
 
-        # Handle proxy models automatically created by .only() or .defer()
+        # Handle proxy models automatically created by .only() or .defer().
+        # Refs #14529
         verbose_name = opts.verbose_name
+        module_name = opts.module_name
         if obj._deferred:
             opts_ = opts.proxy_for_model._meta
             verbose_name = opts_.verbose_name
+            module_name = opts_.module_name
 
         pk_value = obj._get_pk_val()
 
@@ -805,19 +812,28 @@ class ModelAdmin(BaseModelAdmin):
         elif "_saveasnew" in request.POST:
             msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj}
             self.message_user(request, msg)
-            return HttpResponseRedirect("../%s/" % pk_value)
+            return HttpResponseRedirect(reverse('admin:%s_%s_change' %
+                                        (opts.app_label, module_name),
+                                        args=(pk_value,),
+                                        current_app=self.admin_site.name))
         elif "_addanother" in request.POST:
             self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(verbose_name)))
-            return HttpResponseRedirect("../add/")
+            return HttpResponseRedirect(reverse('admin:%s_%s_add' %
+                                        (opts.app_label, module_name),
+                                        current_app=self.admin_site.name))
         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):
-                return HttpResponseRedirect('../')
+                post_url = reverse('admin:%s_%s_changelist' %
+                                   (opts.app_label, module_name),
+                                   current_app=self.admin_site.name)
             else:
-                return HttpResponseRedirect('../../../')
+                post_url = reverse('admin:index',
+                                   current_app=self.admin_site.name)
+            return HttpResponseRedirect(post_url)
 
     def response_action(self, request, queryset):
         """
@@ -990,7 +1006,9 @@ class ModelAdmin(BaseModelAdmin):
             raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)})
 
         if request.method == 'POST' and "_saveasnew" in request.POST:
-            return self.add_view(request, form_url='../add/')
+            return self.add_view(request, form_url=reverse('admin:%s_%s_add' %
+                                    (opts.app_label, opts.module_name),
+                                    current_app=self.admin_site.name))
 
         ModelForm = self.get_form(request, obj)
         formsets = []
@@ -1246,8 +1264,11 @@ class ModelAdmin(BaseModelAdmin):
             self.message_user(request, _('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(reverse('admin:index',
+                                                    current_app=self.admin_site.name))
+            return HttpResponseRedirect(reverse('admin:%s_%s_changelist' %
+                                        (opts.app_label, opts.module_name),
+                                        current_app=self.admin_site.name))
 
         object_name = force_unicode(opts.verbose_name)
 
@@ -1292,6 +1313,7 @@ class ModelAdmin(BaseModelAdmin):
             'module_name': capfirst(force_unicode(opts.verbose_name_plural)),
             'object': obj,
             'app_label': app_label,
+            'opts': opts,
         }
         context.update(extra_context or {})
         return TemplateResponse(request, self.object_history_template or [
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 9bb9f4a..3a5c12b 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -339,9 +339,11 @@ class AdminSite(object):
                 # Check whether user has any perm for this module.
                 # If so, add the module to the model_list.
                 if True in perms.values():
+                    info = (app_label, model._meta.module_name)
                     model_dict = {
                         'name': capfirst(model._meta.verbose_name_plural),
-                        'admin_url': mark_safe('%s/%s/' % (app_label, model.__name__.lower())),
+                        'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name),
+                        'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name),
                         'perms': perms,
                     }
                     if app_label in app_dict:
@@ -349,7 +351,7 @@ class AdminSite(object):
                     else:
                         app_dict[app_label] = {
                             'name': app_label.title(),
-                            'app_url': app_label + '/',
+                            'app_url': reverse('admin:app_list', kwargs={'app_label': app_label}, current_app=self.name),
                             'has_module_perms': has_module_perms,
                             'models': [model_dict],
                         }
@@ -383,9 +385,11 @@ class AdminSite(object):
                     # Check whether user has any perm for this module.
                     # If so, add the module to the model_list.
                     if True in perms.values():
+                        info = (app_label, model._meta.module_name)
                         model_dict = {
                             'name': capfirst(model._meta.verbose_name_plural),
-                            'admin_url': '%s/' % model.__name__.lower(),
+                            'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name),
+                            'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name),
                             'perms': perms,
                         }
                         if app_dict:
diff --git a/django/contrib/admin/templates/admin/500.html b/django/contrib/admin/templates/admin/500.html
index b30e431..eeb9e8d 100644
--- a/django/contrib/admin/templates/admin/500.html
+++ b/django/contrib/admin/templates/admin/500.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans "Home" %}</a> &rsaquo; {% trans "Server error" %}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Server error' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Server error (500)' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/admin/app_index.html b/django/contrib/admin/templates/admin/app_index.html
index 120433d..4616b16 100644
--- a/django/contrib/admin/templates/admin/app_index.html
+++ b/django/contrib/admin/templates/admin/app_index.html
@@ -1,15 +1,17 @@
-{% extends "admin/index.html" %} 
-{% load i18n %} 
+{% extends "admin/index.html" %}
+{% load i18n %}
+{% load url from future %}
 
 {% if not is_popup %}
-
 {% block breadcrumbs %}
-<div class="breadcrumbs"><a href="../">
-{% trans "Home" %}</a> &rsaquo; 
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo;
 {% for app in app_list %}
 {% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}
-{% endfor %}</div>{% endblock %}
-
-{% endif %} 
+{% endfor %}
+</div>
+{% endblock %}
+{% endif %}
 
-{% block sidebar %}{% endblock %}
\ No newline at end of file
+{% block sidebar %}{% endblock %}
diff --git a/django/contrib/admin/templates/admin/auth/user/change_password.html b/django/contrib/admin/templates/admin/auth/user/change_password.html
index b18b0aa..32dbcd9 100644
--- a/django/contrib/admin/templates/admin/auth/user/change_password.html
+++ b/django/contrib/admin/templates/admin/auth/user/change_password.html
@@ -1,21 +1,24 @@
 {% extends "admin/base_site.html" %}
 {% load i18n admin_static admin_modify %}
 {% load url from future %}
+{% load admin_urls %}
+
 {% block extrahead %}{{ block.super }}
 {% url 'admin:jsi18n' as jsi18nurl %}
 <script type="text/javascript" src="{{ jsi18nurl|default:"../../../../jsi18n/" }}"></script>
 {% endblock %}
 {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
 {% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
-{% block breadcrumbs %}{% if not is_popup %}
-<div class="breadcrumbs">
-     <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
-     <a href="../../../">{{ opts.app_label|capfirst|escape }}</a> &rsaquo;
-     <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
-     <a href="../">{{ original|truncatewords:"18" }}</a> &rsaquo;
-     {% trans 'Change password' %}
+{% if not is_popup %}
+{% block breadcrumbs %}
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_label|capfirst|escape }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}{{ original.pk }}">{{ original|truncatewords:"18" }}</a>
+&rsaquo; {% trans 'Change password' %}
 </div>
-{% endif %}{% endblock %}
+{% endblock %}
+{% endif %}
 {% block content %}<div id="content-main">
 <form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %}
 <div>
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index 4b3c429..3b50adc 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -32,17 +32,20 @@
                 {% if docsroot %}
                     <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
                 {% endif %}
-                <a href="{% url 'admin:password_change' %}">
-                {% trans 'Change password' %}</a> /
-                <a href="{% url 'admin:logout' %}">
-                {% trans 'Log out' %}</a>
+                <a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
+                <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
             {% endblock %}
         </div>
         {% endif %}
         {% block nav-global %}{% endblock %}
     </div>
     <!-- END Header -->
-    {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} &rsaquo; {{ title }}{% endif %}</div>{% endblock %}
+    {% block breadcrumbs %}
+    <div class="breadcrumbs">
+    <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+    {% if title %} &rsaquo; {{ title }}{% endif %}
+    </div>
+    {% endblock %}
     {% endif %}
 
     {% block messages %}
diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html
index 56661e9..71230e4 100644
--- a/django/contrib/admin/templates/admin/change_form.html
+++ b/django/contrib/admin/templates/admin/change_form.html
@@ -1,6 +1,7 @@
 {% extends "admin/base_site.html" %}
 {% load i18n admin_static admin_modify %}
 {% load url from future %}
+{% load admin_urls %}
 
 {% block extrahead %}{{ block.super }}
 {% url 'admin:jsi18n' as jsi18nurl %}
@@ -14,14 +15,15 @@
 
 {% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
 
-{% block breadcrumbs %}{% if not is_popup %}
-<div class="breadcrumbs">
-     <a href="../../../">{% trans "Home" %}</a> &rsaquo;
-     <a href="../../">{{ app_label|capfirst|escape }}</a> &rsaquo;
-     {% if has_change_permission %}<a href="../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} &rsaquo;
-     {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
+{% if not is_popup %}
+{% block breadcrumbs %}
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst|escape }}</a>
+&rsaquo; {% if has_change_permission %}<a href="{% url opts|admin_url:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
+&rsaquo; {% if add %}{% trans 'Add' %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
 </div>
-{% endif %}{% endblock %}
+{% endblock %}
+{% endif %}
 
 {% block content %}<div id="content-main">
 {% block object-tools %}
diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html
index 24c6d8c..6a92496 100644
--- a/django/contrib/admin/templates/admin/change_list.html
+++ b/django/contrib/admin/templates/admin/change_list.html
@@ -1,6 +1,8 @@
 {% extends "admin/base_site.html" %}
 {% load i18n admin_static admin_list %}
 {% load url from future %}
+{% load admin_urls %}
+
 {% block extrastyle %}
   {{ block.super }}
   <link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}" />
@@ -36,19 +38,13 @@
 {% block bodyclass %}change-list{% endblock %}
 
 {% if not is_popup %}
-  {% block breadcrumbs %}
-    <div class="breadcrumbs">
-      <a href="../../">
-        {% trans "Home" %}
-      </a>
-       &rsaquo;
-       <a href="../">
-         {{ app_label|capfirst }}
-      </a>
-      &rsaquo;
-      {{ cl.opts.verbose_name_plural|capfirst }}
-    </div>
-  {% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ app_label|capfirst|escape }}</a>
+&rsaquo; {{ cl.opts.verbose_name_plural|capfirst }}
+</div>
+{% endblock %}
 {% endif %}
 
 {% block coltype %}flex{% endblock %}
@@ -60,7 +56,7 @@
         <ul class="object-tools">
           {% block object-tools-items %}
             <li>
-              <a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
+              <a href="{% url cl.opts|admin_url:'add' %}{% if is_popup %}?_popup=1{% endif %}" class="addlink">
                 {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
               </a>
             </li>
diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html
index 0e6d47e..a4acb95 100644
--- a/django/contrib/admin/templates/admin/delete_confirmation.html
+++ b/django/contrib/admin/templates/admin/delete_confirmation.html
@@ -1,13 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+{% load admin_urls %}
 
 {% block breadcrumbs %}
 <div class="breadcrumbs">
-     <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
-     <a href="../../../">{{ app_label|capfirst }}</a> &rsaquo; 
-     <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
-     <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo;
-     {% trans 'Delete' %}
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}">{{ opts.verbose_name_plural|capfirst|escape }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}{{ object.pk }}">{{ object|truncatewords:"18" }}</a>
+&rsaquo; {% trans 'Delete' %}
 </div>
 {% endblock %}
 
diff --git a/django/contrib/admin/templates/admin/delete_selected_confirmation.html b/django/contrib/admin/templates/admin/delete_selected_confirmation.html
index 127519b..04a2ae7 100644
--- a/django/contrib/admin/templates/admin/delete_selected_confirmation.html
+++ b/django/contrib/admin/templates/admin/delete_selected_confirmation.html
@@ -1,12 +1,14 @@
 {% extends "admin/base_site.html" %}
 {% load i18n l10n %}
+{% load url from future %}
+{% load admin_urls %}
 
 {% block breadcrumbs %}
 <div class="breadcrumbs">
-     <a href="../../">{% trans "Home" %}</a> &rsaquo;
-     <a href="../">{{ app_label|capfirst }}</a> &rsaquo;
-     <a href="./">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
-     {% trans 'Delete multiple objects' %}
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
+&rsaquo; {% trans 'Delete multiple objects' %}
 </div>
 {% endblock %}
 
diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html
index 7164220..86c795b 100644
--- a/django/contrib/admin/templates/admin/index.html
+++ b/django/contrib/admin/templates/admin/index.html
@@ -26,7 +26,7 @@
             {% endif %}
 
             {% if model.perms.add %}
-                <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
+                <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
             {% else %}
                 <td>&nbsp;</td>
             {% endif %}
diff --git a/django/contrib/admin/templates/admin/invalid_setup.html b/django/contrib/admin/templates/admin/invalid_setup.html
index f09b316..c2df4df 100644
--- a/django/contrib/admin/templates/admin/invalid_setup.html
+++ b/django/contrib/admin/templates/admin/invalid_setup.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title }}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {{ title }}
+</div>
+{% endblock %}
 
 {% block content %}
 <p>{% trans "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." %}</p>
diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html
index 5ae7847..e39471b 100644
--- a/django/contrib/admin/templates/admin/object_history.html
+++ b/django/contrib/admin/templates/admin/object_history.html
@@ -1,13 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+{% load admin_urls %}
 
 {% block breadcrumbs %}
 <div class="breadcrumbs">
-    <a href="../../../../">{% trans 'Home' %}</a> &rsaquo; 
-    <a href="../../../">{{ app_label|capfirst }}</a> &rsaquo; 
-    <a href="../../">{{ module_name }}</a> &rsaquo; 
-    <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; 
-    {% trans 'History' %}
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}">{{ module_name }}</a>
+&rsaquo; <a href="{% url opts|admin_url:'changelist' %}{{ object.pk }}">{{ object|truncatewords:"18" }}</a>
+&rsaquo; {% trans 'History' %}
 </div>
 {% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/logged_out.html b/django/contrib/admin/templates/registration/logged_out.html
index d339ef0..e95d864 100644
--- a/django/contrib/admin/templates/registration/logged_out.html
+++ b/django/contrib/admin/templates/registration/logged_out.html
@@ -1,12 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a></div>{% endblock %}
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></div>{% endblock %}
 
 {% block content %}
 
 <p>{% trans "Thanks for spending some quality time with the Web site today." %}</p>
 
-<p><a href="../">{% trans 'Log in again' %}</a></p>
+<p><a href="{% url 'admin:index' %}">{% trans 'Log in again' %}</a></p>
 
 {% endblock %}
diff --git a/django/contrib/admin/templates/registration/password_change_done.html b/django/contrib/admin/templates/registration/password_change_done.html
index 0c0690d..863fc96 100644
--- a/django/contrib/admin/templates/registration/password_change_done.html
+++ b/django/contrib/admin/templates/registration/password_change_done.html
@@ -1,8 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
 {% load url from future %}
-{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
+{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password change' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Password change successful' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/password_change_form.html b/django/contrib/admin/templates/registration/password_change_form.html
index f76692d..0e4ea53 100644
--- a/django/contrib/admin/templates/registration/password_change_form.html
+++ b/django/contrib/admin/templates/registration/password_change_form.html
@@ -2,8 +2,13 @@
 {% load i18n static %}
 {% load url from future %}
 {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
-{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password change' %}</div>{% endblock %}
+{% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password change' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Password change' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/password_reset_complete.html b/django/contrib/admin/templates/registration/password_reset_complete.html
index fceb167..7c07707 100644
--- a/django/contrib/admin/templates/registration/password_reset_complete.html
+++ b/django/contrib/admin/templates/registration/password_reset_complete.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password reset' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Password reset complete' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/password_reset_confirm.html b/django/contrib/admin/templates/registration/password_reset_confirm.html
index df9cf1b..d5299eb 100644
--- a/django/contrib/admin/templates/registration/password_reset_confirm.html
+++ b/django/contrib/admin/templates/registration/password_reset_confirm.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset confirmation' %}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password reset confirmation' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Password reset' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/password_reset_done.html b/django/contrib/admin/templates/registration/password_reset_done.html
index e223bdb..fd73af8 100644
--- a/django/contrib/admin/templates/registration/password_reset_done.html
+++ b/django/contrib/admin/templates/registration/password_reset_done.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password reset' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans 'Password reset successful' %}{% endblock %}
 
diff --git a/django/contrib/admin/templates/registration/password_reset_form.html b/django/contrib/admin/templates/registration/password_reset_form.html
index d3a1284..2b591fe 100644
--- a/django/contrib/admin/templates/registration/password_reset_form.html
+++ b/django/contrib/admin/templates/registration/password_reset_form.html
@@ -1,7 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> &rsaquo; {% trans 'Password reset' %}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Password reset' %}
+</div>
+{% endblock %}
 
 {% block title %}{% trans "Password reset" %}{% endblock %}
 
diff --git a/django/contrib/admin/templatetags/admin_urls.py b/django/contrib/admin/templatetags/admin_urls.py
new file mode 100644
index 0000000..15e4649
--- /dev/null
+++ b/django/contrib/admin/templatetags/admin_urls.py
@@ -0,0 +1,8 @@
+from django.core.urlresolvers import reverse, NoReverseMatch
+from django import template
+
+register = template.Library()
+
+@register.filter
+def admin_url(value, arg):
+    return 'admin:%s_%s_%s' % (value.app_label, value.module_name, arg)
diff --git a/django/contrib/admindocs/templates/admin_doc/bookmarklets.html b/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
index 6447529..baa717c 100644
--- a/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
+++ b/django/contrib/admindocs/templates/admin_doc/bookmarklets.html
@@ -1,6 +1,14 @@
 {% extends "admin/base_site.html" %}
-
-{% block breadcrumbs %}{% load i18n %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; <a href="../">{% trans "Documentation" %}</a> &rsaquo; {% trans "Bookmarklets" %}</div>{% endblock %}
+{% load i18n %}
+{% load url from future %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Bookmarklets' %}
+</div>
+{% endblock %}
 {% block title %}{% trans "Documentation bookmarklets" %}{% endblock %}
 
 {% block content %}
diff --git a/django/contrib/admindocs/templates/admin_doc/index.html b/django/contrib/admindocs/templates/admin_doc/index.html
index a8b21c3..652fbfd 100644
--- a/django/contrib/admindocs/templates/admin_doc/index.html
+++ b/django/contrib/admindocs/templates/admin_doc/index.html
@@ -1,6 +1,13 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="{{ root_path }}">Home</a> &rsaquo; Documentation</div>{% endblock %}
+{% load url from future %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Documentation' %}</a>
+</div>
+{% endblock %}
 {% block title %}Documentation{% endblock %}
 
 {% block content %}
diff --git a/django/contrib/admindocs/templates/admin_doc/missing_docutils.html b/django/contrib/admindocs/templates/admin_doc/missing_docutils.html
index 97c9d47..34c18ff 100644
--- a/django/contrib/admindocs/templates/admin_doc/missing_docutils.html
+++ b/django/contrib/admindocs/templates/admin_doc/missing_docutils.html
@@ -1,6 +1,12 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> &rsaquo; Documentation</div>{% endblock %}
+{% load url from future %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; {% trans 'Documentation' %}</a>
+</div>
 {% block title %}Please install docutils{% endblock %}
 
 {% block content %}
diff --git a/django/contrib/admindocs/templates/admin_doc/model_detail.html b/django/contrib/admindocs/templates/admin_doc/model_detail.html
index 828df18..82cb405 100644
--- a/django/contrib/admindocs/templates/admin_doc/model_detail.html
+++ b/django/contrib/admindocs/templates/admin_doc/model_detail.html
@@ -1,5 +1,7 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+
 {% block extrahead %}
 {{ block.super }}
 <style type="text/css">
@@ -8,7 +10,14 @@
 </style>
 {% endblock %}
 
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Models</a> &rsaquo; {{ name }}</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-models-index' %}">{% trans 'Models' %}</a>
+&rsaquo; {{ name }}
+</div>
+{% endblock %}
 
 {% block title %}Model: {{ name }}{% endblock %}
 
@@ -41,6 +50,6 @@
 </table>
 </div>
 
-<p class="small"><a href="../">&lsaquo; Back to Models Documentation</a></p>
+<p class="small"><a href="{% url 'django-admindocs-models-index' %}">&lsaquo; Back to Models Documentation</a></p>
 </div>
 {% endblock %}
diff --git a/django/contrib/admindocs/templates/admin_doc/model_index.html b/django/contrib/admindocs/templates/admin_doc/model_index.html
index 47c94c0..4eb3cf6 100644
--- a/django/contrib/admindocs/templates/admin_doc/model_index.html
+++ b/django/contrib/admindocs/templates/admin_doc/model_index.html
@@ -1,7 +1,16 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+
 {% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Models</div>{% endblock %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Models' %}
+</div>
+{% endblock %}
 
 {% block title %}Models{% endblock %}
 
@@ -19,7 +28,7 @@
 <table class="xfull">
 {% for model in group.list %}
 <tr>
-<th><a href="{{ model.app_label }}.{{ model.object_name.lower }}/">{{ model.object_name }}</a></th>
+<th><a href="{% url 'django-admindocs-models-detail' app_label=model.app_label model_name=model.object_name.lower %}">{{ model.object_name }}</a></th>
 </tr>
 {% endfor %}
 </table>
diff --git a/django/contrib/admindocs/templates/admin_doc/template_detail.html b/django/contrib/admindocs/templates/admin_doc/template_detail.html
index c04dedc..307dd62 100644
--- a/django/contrib/admindocs/templates/admin_doc/template_detail.html
+++ b/django/contrib/admindocs/templates/admin_doc/template_detail.html
@@ -1,6 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; Templates &rsaquo; {{ name }}</div>{% endblock %}
+{% load url from future %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Templates' %}
+&rsaquo; {{ name }}
+</div>
+{% endblock %}
 
 {% block title %}Template: {{ name }}{% endblock %}
 
@@ -17,5 +26,5 @@
     </ol>
 {% endfor %}
 
-<p class="small"><a href="../../">&lsaquo; Back to Documentation</a></p>
+<p class="small"><a href="{% url 'django-admindocs-docroot' %}">&lsaquo; Back to Documentation</a></p>
 {% endblock %}
diff --git a/django/contrib/admindocs/templates/admin_doc/template_filter_index.html b/django/contrib/admindocs/templates/admin_doc/template_filter_index.html
index 46ccf0f..1809bc9 100644
--- a/django/contrib/admindocs/templates/admin_doc/template_filter_index.html
+++ b/django/contrib/admindocs/templates/admin_doc/template_filter_index.html
@@ -1,7 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+
 {% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; filters</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Filters' %}
+</div>
+{% endblock %}
 {% block title %}Template filters{% endblock %}
 
 {% block content %}
diff --git a/django/contrib/admindocs/templates/admin_doc/template_tag_index.html b/django/contrib/admindocs/templates/admin_doc/template_tag_index.html
index 676c025..18e5d95 100644
--- a/django/contrib/admindocs/templates/admin_doc/template_tag_index.html
+++ b/django/contrib/admindocs/templates/admin_doc/template_tag_index.html
@@ -1,7 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+
 {% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Tags</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Tags' %}
+</div>
+{% endblock %}
 {% block title %}Template tags{% endblock %}
 
 {% block content %}
diff --git a/django/contrib/admindocs/templates/admin_doc/view_detail.html b/django/contrib/admindocs/templates/admin_doc/view_detail.html
index c6d080c..41c8121 100644
--- a/django/contrib/admindocs/templates/admin_doc/view_detail.html
+++ b/django/contrib/admindocs/templates/admin_doc/view_detail.html
@@ -1,6 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Views</a> &rsaquo; {{ name }}</div>{% endblock %}
+{% load url from future %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-views-index' %}">{% trans 'Views' %}</a>
+&rsaquo; {{ name }}
+</div>
+{% endblock %}
 {% block title %}View: {{ name }}{% endblock %}
 
 {% block content %}
@@ -21,5 +30,5 @@
 <p>{{ meta.Templates }}</p>
 {% endif %}
 
-<p class="small"><a href="../">&lsaquo; Back to Views Documentation</a></p>
+<p class="small"><a href="{% url 'django-admindocs-views-index' %}">&lsaquo; Back to Views Documentation</a></p>
 {% endblock %}
diff --git a/django/contrib/admindocs/templates/admin_doc/view_index.html b/django/contrib/admindocs/templates/admin_doc/view_index.html
index 6b10fa6..e508c84 100644
--- a/django/contrib/admindocs/templates/admin_doc/view_index.html
+++ b/django/contrib/admindocs/templates/admin_doc/view_index.html
@@ -1,7 +1,15 @@
 {% extends "admin/base_site.html" %}
 {% load i18n %}
+{% load url from future %}
+
 {% block coltype %}colSM{% endblock %}
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> &rsaquo; <a href="../">Documentation</a> &rsaquo; Views</div>{% endblock %}
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a>
+&rsaquo; {% trans 'Views' %}
+</div>
+{% endblock %}
 {% block title %}Views{% endblock %}
 
 {% block content %}
@@ -29,8 +37,8 @@
 
 {% for view in site_views.list|dictsort:"url" %}
 {% ifchanged %}
-<h3><a href="{{ view.module }}.{{ view.name }}/">{{ view.url }}</a></h3>
-<p class="small quiet">View function: {{ view.module }}.{{ view.name }}</p>
+<h3><a href="{% url 'django-admindocs-views-detail' view=view.full_name %}">{{ view.url }}</a></h3>
+<p class="small quiet">View function: {{ view.full_name }}</p>
 <p>{{ view.title }}</p>
 <hr />
 {% endifchanged %}
diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py
index 28319be..9725865 100644
--- a/django/contrib/admindocs/views.py
+++ b/django/contrib/admindocs/views.py
@@ -136,8 +136,7 @@ def view_index(request):
             site_obj = GenericSite()
         for (func, regex) in view_functions:
             views.append({
-                'name': getattr(func, '__name__', func.__class__.__name__),
-                'module': func.__module__,
+                'full_name': '%s.%s' % (func.__module__, getattr(func, '__name__', func.__class__.__name__)),
                 'site_id': settings_mod.SITE_ID,
                 'site': site_obj,
                 'url': simplify_regex(regex),
diff --git a/tests/regressiontests/admin_changelist/admin.py b/tests/regressiontests/admin_changelist/admin.py
new file mode 100644
index 0000000..9490cd5
--- /dev/null
+++ b/tests/regressiontests/admin_changelist/admin.py
@@ -0,0 +1,67 @@
+from django.core.paginator import Paginator
+from django.contrib import admin
+
+from models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
+    Membership, ChordsMusician, ChordsBand, Invitation)
+
+site = admin.AdminSite(name="admin")
+
+class CustomPaginator(Paginator):
+    def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
+        super(CustomPaginator, self).__init__(queryset, 5, orphans=2,
+            allow_empty_first_page=allow_empty_first_page)
+
+
+class ParentAdmin(admin.ModelAdmin):
+    list_filter = ['child__name']
+    search_fields = ['child__name']
+
+
+class ChildAdmin(admin.ModelAdmin):
+    list_display = ['name', 'parent']
+    list_per_page = 10
+
+    def queryset(self, request):
+        return super(ChildAdmin, self).queryset(request).select_related("parent__name")
+
+
+class CustomPaginationAdmin(ChildAdmin):
+    paginator = CustomPaginator
+
+
+class FilteredChildAdmin(admin.ModelAdmin):
+    list_display = ['name', 'parent']
+    list_per_page = 10
+
+    def queryset(self, request):
+        return super(FilteredChildAdmin, self).queryset(request).filter(
+            name__contains='filtered')
+
+
+class BandAdmin(admin.ModelAdmin):
+    list_filter = ['genres']
+
+
+class GroupAdmin(admin.ModelAdmin):
+    list_filter = ['members']
+
+
+class QuartetAdmin(admin.ModelAdmin):
+    list_filter = ['members']
+
+
+class ChordsBandAdmin(admin.ModelAdmin):
+    list_filter = ['members']
+
+
+class DynamicListDisplayChildAdmin(admin.ModelAdmin):
+    list_display = ('name', 'parent')
+
+    def get_list_display(self, request):
+        my_list_display = list(self.list_display)
+        if request.user.username == 'noparents':
+            my_list_display.remove('parent')
+
+        return my_list_display
+
+site.register(Child, DynamicListDisplayChildAdmin)
diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py
index 09ec190..83ce6e3 100644
--- a/tests/regressiontests/admin_changelist/tests.py
+++ b/tests/regressiontests/admin_changelist/tests.py
@@ -3,7 +3,6 @@ from __future__ import with_statement
 from django.contrib import admin
 from django.contrib.admin.options import IncorrectLookupParameters
 from django.contrib.admin.views.main import ChangeList, SEARCH_VAR, ALL_VAR
-from django.core.paginator import Paginator
 from django.template import Context, Template
 from django.test import TestCase
 from django.test.client import RequestFactory
@@ -12,8 +11,14 @@ from django.contrib.auth.models import User
 from models import (Child, Parent, Genre, Band, Musician, Group, Quartet,
     Membership, ChordsMusician, ChordsBand, Invitation)
 
+from admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin,
+    GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, CustomPaginationAdmin,
+    FilteredChildAdmin, CustomPaginator, site as custom_site)
+
 
 class ChangeListTests(TestCase):
+    urls = "regressiontests.admin_changelist.urls"
+
     def setUp(self):
         self.factory = RequestFactory()
 
@@ -129,11 +134,7 @@ class ChangeListTests(TestCase):
             new_child = Child.objects.create(name='name %s' % i, parent=new_parent)
 
         request = self.factory.get('/child/')
-        m = ChildAdmin(Child, admin.site)
-        m.list_display = ['id', 'name', 'parent']
-        m.list_display_links = ['id']
-        m.list_editable = ['name']
-        m.paginator = CustomPaginator
+        m = CustomPaginationAdmin(Child, admin.site)
 
         cl = ChangeList(request, Child, m.list_display, m.list_display_links,
                 m.list_filter, m.date_hierarchy, m.search_fields,
@@ -330,8 +331,8 @@ class ChangeListTests(TestCase):
             request.user = user
             return request
 
+        m = custom_site._registry[Child]
         # Test with user 'noparents'
-        m = DynamicListDisplayChildAdmin(Child, admin.site)
         request = _mocked_authenticated_request(user_noparents)
         response = m.changelist_view(request)
         # XXX - Calling render here to avoid ContentNotRenderedError to be
@@ -340,15 +341,16 @@ class ChangeListTests(TestCase):
         self.assertNotContains(response, 'Parent object')
 
         # Test with user 'parents'
-        m = DynamicListDisplayChildAdmin(Child, admin.site)
         request = _mocked_authenticated_request(user_parents)
         response = m.changelist_view(request)
         # XXX - #15826
         response.render()
         self.assertContains(response, 'Parent object')
 
+        custom_site.unregister(Child)
         # Test default implementation
-        m = ChildAdmin(Child, admin.site)
+        custom_site.register(Child, ChildAdmin)
+        m = custom_site._registry[Child]
         request = _mocked_authenticated_request(user_noparents)
         response = m.changelist_view(request)
         # XXX - #15826
@@ -383,57 +385,3 @@ class ChangeListTests(TestCase):
         cl.get_results(request)
         self.assertEqual(len(cl.result_list), 10)
 
-
-class ParentAdmin(admin.ModelAdmin):
-    list_filter = ['child__name']
-    search_fields = ['child__name']
-
-
-class ChildAdmin(admin.ModelAdmin):
-    list_display = ['name', 'parent']
-    list_per_page = 10
-
-    def queryset(self, request):
-        return super(ChildAdmin, self).queryset(request).select_related("parent__name")
-
-
-class FilteredChildAdmin(admin.ModelAdmin):
-    list_display = ['name', 'parent']
-    list_per_page = 10
-
-    def queryset(self, request):
-        return super(FilteredChildAdmin, self).queryset(request).filter(
-            name__contains='filtered')
-
-
-class CustomPaginator(Paginator):
-    def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):
-        super(CustomPaginator, self).__init__(queryset, 5, orphans=2,
-            allow_empty_first_page=allow_empty_first_page)
-
-
-class BandAdmin(admin.ModelAdmin):
-    list_filter = ['genres']
-
-
-class GroupAdmin(admin.ModelAdmin):
-    list_filter = ['members']
-
-
-class QuartetAdmin(admin.ModelAdmin):
-    list_filter = ['members']
-
-
-class ChordsBandAdmin(admin.ModelAdmin):
-    list_filter = ['members']
-
-
-class DynamicListDisplayChildAdmin(admin.ModelAdmin):
-    list_display = ('name', 'parent')
-
-    def get_list_display(self, request):
-        my_list_display = list(self.list_display)
-        if request.user.username == 'noparents':
-            my_list_display.remove('parent')
-
-        return my_list_display
diff --git a/tests/regressiontests/admin_changelist/urls.py b/tests/regressiontests/admin_changelist/urls.py
new file mode 100644
index 0000000..1cbb496
--- /dev/null
+++ b/tests/regressiontests/admin_changelist/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+
+import admin
+
+urlpatterns = patterns('',
+    (r'^admin/', include(admin.site.urls)),
+)
diff --git a/tests/regressiontests/admin_custom_urls/__init__.py b/tests/regressiontests/admin_custom_urls/__init__.py
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/__init__.py
@@ -0,0 +1 @@
+#
diff --git a/tests/regressiontests/admin_custom_urls/fixtures/actions.json b/tests/regressiontests/admin_custom_urls/fixtures/actions.json
new file mode 100644
index 0000000..d803393
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/fixtures/actions.json
@@ -0,0 +1,44 @@
+[
+  {
+    "pk": "delete", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "Remove things."
+    }
+  }, 
+  {
+    "pk": "rename", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "Gives things other names."
+    }
+  }, 
+  {
+    "pk": "add", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "Add things."
+    }
+  }, 
+  {
+    "pk": "path/to/file/", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "An action with '/' in its name."
+    }
+  }, 
+  {
+    "pk": "path/to/html/document.html", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "An action with a name similar to a HTML doc path."
+    }
+  }, 
+  {
+    "pk": "javascript:alert('Hello world');\">Click here</a>", 
+    "model": "admin_custom_urls.action", 
+    "fields": {
+      "description": "An action with a name suspected of being a XSS attempt"
+    }
+  }
+]
\ No newline at end of file
diff --git a/tests/regressiontests/admin_custom_urls/fixtures/users.json b/tests/regressiontests/admin_custom_urls/fixtures/users.json
new file mode 100644
index 0000000..72d86d7
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/fixtures/users.json
@@ -0,0 +1,20 @@
+[
+  {
+    "pk": 100,
+    "model": "auth.user",
+    "fields": {
+      "username": "super",
+      "first_name": "Super",
+      "last_name": "User",
+      "is_active": true,
+      "is_superuser": true,
+      "is_staff": true,
+      "last_login": "2007-05-30 13:20:10",
+      "groups": [],
+      "user_permissions": [],
+      "password": "sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158",
+      "email": "super@example.com",
+      "date_joined": "2007-05-30 13:20:10"
+    }
+  }
+]
diff --git a/tests/regressiontests/admin_custom_urls/models.py b/tests/regressiontests/admin_custom_urls/models.py
new file mode 100644
index 0000000..f8c83a9
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/models.py
@@ -0,0 +1,50 @@
+from functools import update_wrapper
+
+from django.contrib import admin
+from django.db import models
+
+
+class Action(models.Model):
+    name = models.CharField(max_length=50, primary_key=True)
+    description = models.CharField(max_length=70)
+
+    def __unicode__(self):
+        return self.name
+
+
+class ActionAdmin(admin.ModelAdmin):
+    """
+    A ModelAdmin for the Action model that changes the URL of the add_view
+    to '<app name>/<model name>/!add/'
+    The Action model has a CharField PK.
+    """
+
+    list_display = ('name', 'description')
+
+    def remove_url(self, name):
+        """
+        Remove all entries named 'name' from the ModelAdmin instance URL
+        patterns list
+        """
+        return filter(lambda e: e.name != name, super(ActionAdmin, self).get_urls())
+
+    def get_urls(self):
+        # Add the URL of our custom 'add_view' view to the front of the URLs
+        # list.  Remove the existing one(s) first
+        from django.conf.urls.defaults import patterns, url
+
+        def wrap(view):
+            def wrapper(*args, **kwargs):
+                return self.admin_site.admin_view(view)(*args, **kwargs)
+            return update_wrapper(wrapper, view)
+
+        info = self.model._meta.app_label, self.model._meta.module_name
+
+        view_name = '%s_%s_add' % info
+
+        return patterns('',
+            url(r'^!add/$', wrap(self.add_view), name=view_name),
+        ) + self.remove_url(view_name)
+
+
+admin.site.register(Action, ActionAdmin)
diff --git a/tests/regressiontests/admin_custom_urls/tests.py b/tests/regressiontests/admin_custom_urls/tests.py
new file mode 100644
index 0000000..cfc6b85
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/tests.py
@@ -0,0 +1,72 @@
+from django.core.urlresolvers import reverse
+from django.template.response import TemplateResponse
+from django.test import TestCase
+
+from models import Action
+
+
+class AdminCustomUrlsTest(TestCase):
+    fixtures = ['users.json', 'actions.json']
+
+    def setUp(self):
+        self.client.login(username='super', password='secret')
+
+    def tearDown(self):
+        self.client.logout()
+
+    def testBasicAddGet(self):
+        """
+        A smoke test to ensure GET on the add_view works.
+        """
+        response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/')
+        self.assertIsInstance(response, TemplateResponse)
+        self.assertEqual(response.status_code, 200)
+
+    def testAddWithGETArgs(self):
+        response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/', {'name': 'My Action'})
+        self.assertEqual(response.status_code, 200)
+        self.assertTrue(
+            'value="My Action"' in response.content,
+            "Couldn't find an input with the right value in the response."
+        )
+
+    def testBasicAddPost(self):
+        """
+        A smoke test to ensure POST on add_view works.
+        """
+        post_data = {
+            '_popup': u'1',
+            "name": u'Action added through a popup',
+            "description": u"Description of added action",
+        }
+        response = self.client.post('/custom_urls/admin/admin_custom_urls/action/!add/', post_data)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'dismissAddAnotherPopup')
+        self.assertContains(response, 'Action added through a popup')
+
+    def testAdminUrlsNoClash(self):
+        """
+        Test that some admin URLs work correctly. The model has a CharField
+        PK and the add_view URL has been customized.
+        """
+        # Should get the change_view for model instance with PK 'add', not show
+        # the add_view
+        response = self.client.get('/custom_urls/admin/admin_custom_urls/action/add/')
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'Change action')
+
+        # Ditto, but use reverse() to build the URL
+        path = reverse('admin:%s_action_change' % Action._meta.app_label,
+                args=('add',))
+        response = self.client.get(path)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'Change action')
+
+        # Should correctly get the change_view for the model instance with the
+        # funny-looking PK
+        path = reverse('admin:%s_action_change' % Action._meta.app_label,
+                args=("path/to/html/document.html",))
+        response = self.client.get(path)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'Change action')
+        self.assertContains(response, 'value="path/to/html/document.html"')
diff --git a/tests/regressiontests/admin_custom_urls/urls.py b/tests/regressiontests/admin_custom_urls/urls.py
new file mode 100644
index 0000000..6c2761a
--- /dev/null
+++ b/tests/regressiontests/admin_custom_urls/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+from django.contrib import admin
+
+urlpatterns = patterns('',
+    (r'^admin/', include(admin.site.urls)),
+)
+
diff --git a/tests/regressiontests/admin_inlines/admin.py b/tests/regressiontests/admin_inlines/admin.py
new file mode 100644
index 0000000..098d7b5
--- /dev/null
+++ b/tests/regressiontests/admin_inlines/admin.py
@@ -0,0 +1,118 @@
+from django.contrib import admin
+from django import forms
+
+from models import *
+
+site = admin.AdminSite(name="admin")
+
+
+class BookInline(admin.TabularInline):
+    model = Author.books.through
+
+
+class AuthorAdmin(admin.ModelAdmin):
+    inlines = [BookInline]
+
+
+class InnerInline(admin.StackedInline):
+    model = Inner
+    can_delete = False
+    readonly_fields = ('readonly',) # For bug #13174 tests.
+
+
+class HolderAdmin(admin.ModelAdmin):
+
+    class Media:
+        js = ('my_awesome_admin_scripts.js',)
+
+
+class InnerInline2(admin.StackedInline):
+    model = Inner2
+
+    class Media:
+        js = ('my_awesome_inline_scripts.js',)
+
+
+class InnerInline3(admin.StackedInline):
+    model = Inner3
+
+    class Media:
+        js = ('my_awesome_inline_scripts.js',)
+
+
+class TitleForm(forms.ModelForm):
+
+    def clean(self):
+        cleaned_data = self.cleaned_data
+        title1 = cleaned_data.get("title1")
+        title2 = cleaned_data.get("title2")
+        if title1 != title2:
+            raise forms.ValidationError("The two titles must be the same")
+        return cleaned_data
+
+
+class TitleInline(admin.TabularInline):
+    model = Title
+    form = TitleForm
+    extra = 1
+
+
+class Inner4StackedInline(admin.StackedInline):
+    model = Inner4Stacked
+
+
+class Inner4TabularInline(admin.TabularInline):
+    model = Inner4Tabular
+
+
+class Holder4Admin(admin.ModelAdmin):
+    inlines = [Inner4StackedInline, Inner4TabularInline]
+
+
+class InlineWeakness(admin.TabularInline):
+    model = ShoppingWeakness
+    extra = 1
+
+
+class QuestionInline(admin.TabularInline):
+    model = Question
+    readonly_fields=['call_me']
+
+    def call_me(self, obj):
+        return 'Callable in QuestionInline'
+
+
+class PollAdmin(admin.ModelAdmin):
+    inlines = [QuestionInline]
+
+    def call_me(self, obj):
+        return 'Callable in PollAdmin'
+
+
+class ChapterInline(admin.TabularInline):
+    model = Chapter
+    readonly_fields=['call_me']
+
+    def call_me(self, obj):
+        return 'Callable in ChapterInline'
+
+
+class NovelAdmin(admin.ModelAdmin):
+    inlines = [ChapterInline]
+
+
+site.register(TitleCollection, inlines=[TitleInline])
+# Test bug #12561 and #12778
+# only ModelAdmin media
+site.register(Holder, HolderAdmin, inlines=[InnerInline])
+# ModelAdmin and Inline media
+site.register(Holder2, HolderAdmin, inlines=[InnerInline2])
+# only Inline media
+site.register(Holder3, inlines=[InnerInline3])
+
+site.register(Poll, PollAdmin)
+site.register(Novel, NovelAdmin)
+site.register(Fashionista, inlines=[InlineWeakness])
+site.register(Holder4, Holder4Admin)
+site.register(Author, AuthorAdmin)
+
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
index 8d9ca7c..f4e58f2 100644
--- a/tests/regressiontests/admin_inlines/models.py
+++ b/tests/regressiontests/admin_inlines/models.py
@@ -3,10 +3,9 @@ Testing of admin inline formsets.
 
 """
 from django.db import models
-from django.contrib import admin
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
-from django import forms
+
 
 class Parent(models.Model):
     name = models.CharField(max_length=50)
@@ -14,12 +13,14 @@ class Parent(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Teacher(models.Model):
     name = models.CharField(max_length=50)
 
     def __unicode__(self):
         return self.name
 
+
 class Child(models.Model):
     name = models.CharField(max_length=50)
     teacher = models.ForeignKey(Teacher)
@@ -31,20 +32,15 @@ class Child(models.Model):
     def __unicode__(self):
         return u'I am %s, a child of %s' % (self.name, self.parent)
 
+
 class Book(models.Model):
     name = models.CharField(max_length=50)
 
+
 class Author(models.Model):
     name = models.CharField(max_length=50)
     books = models.ManyToManyField(Book)
 
-class BookInline(admin.TabularInline):
-    model = Author.books.through
-
-class AuthorAdmin(admin.ModelAdmin):
-    inlines = [BookInline]
-
-admin.site.register(Author, AuthorAdmin)
 
 class Holder(models.Model):
     dummy = models.IntegerField()
@@ -56,12 +52,6 @@ class Inner(models.Model):
     readonly = models.CharField("Inner readonly label", max_length=1)
 
 
-class InnerInline(admin.StackedInline):
-    model = Inner
-    can_delete = False
-    readonly_fields = ('readonly',) # For bug #13174 tests.
-
-
 class Holder2(models.Model):
     dummy = models.IntegerField()
 
@@ -70,17 +60,6 @@ class Inner2(models.Model):
     dummy = models.IntegerField()
     holder = models.ForeignKey(Holder2)
 
-class HolderAdmin(admin.ModelAdmin):
-
-    class Media:
-        js = ('my_awesome_admin_scripts.js',)
-
-class InnerInline2(admin.StackedInline):
-    model = Inner2
-
-    class Media:
-        js = ('my_awesome_inline_scripts.js',)
-
 class Holder3(models.Model):
     dummy = models.IntegerField()
 
@@ -89,21 +68,6 @@ class Inner3(models.Model):
     dummy = models.IntegerField()
     holder = models.ForeignKey(Holder3)
 
-class InnerInline3(admin.StackedInline):
-    model = Inner3
-
-    class Media:
-        js = ('my_awesome_inline_scripts.js',)
-
-# Test bug #12561 and #12778
-# only ModelAdmin media
-admin.site.register(Holder, HolderAdmin, inlines=[InnerInline])
-# ModelAdmin and Inline media
-admin.site.register(Holder2, HolderAdmin, inlines=[InnerInline2])
-# only Inline media
-admin.site.register(Holder3, inlines=[InnerInline3])
-
-
 # Models for ticket #8190
 
 class Holder4(models.Model):
@@ -117,17 +81,6 @@ class Inner4Tabular(models.Model):
     dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.")
     holder = models.ForeignKey(Holder4)
 
-class Inner4StackedInline(admin.StackedInline):
-    model = Inner4Stacked
-
-class Inner4TabularInline(admin.TabularInline):
-    model = Inner4Tabular
-
-class Holder4Admin(admin.ModelAdmin):
-    inlines = [Inner4StackedInline, Inner4TabularInline]
-
-admin.site.register(Holder4, Holder4Admin)
-
 
 # Models for #12749
 
@@ -145,12 +98,6 @@ class ShoppingWeakness(models.Model):
     fashionista = models.ForeignKey(Fashionista)
     item = models.ForeignKey(OutfitItem)
 
-class InlineWeakness(admin.TabularInline):
-    model = ShoppingWeakness
-    extra = 1
-
-admin.site.register(Fashionista, inlines=[InlineWeakness])
-
 # Models for #13510
 
 class TitleCollection(models.Model):
@@ -161,23 +108,6 @@ class Title(models.Model):
     title1 = models.CharField(max_length=100)
     title2 = models.CharField(max_length=100)
 
-class TitleForm(forms.ModelForm):
-
-    def clean(self):
-        cleaned_data = self.cleaned_data
-        title1 = cleaned_data.get("title1")
-        title2 = cleaned_data.get("title2")
-        if title1 != title2:
-            raise forms.ValidationError("The two titles must be the same")
-        return cleaned_data
-
-class TitleInline(admin.TabularInline):
-    model = Title
-    form = TitleForm
-    extra = 1
-
-admin.site.register(TitleCollection, inlines=[TitleInline])
-
 # Models for #15424
 
 class Poll(models.Model):
@@ -186,34 +116,9 @@ class Poll(models.Model):
 class Question(models.Model):
     poll = models.ForeignKey(Poll)
 
-class QuestionInline(admin.TabularInline):
-    model = Question
-    readonly_fields=['call_me']
-
-    def call_me(self, obj):
-        return 'Callable in QuestionInline'
-
-class PollAdmin(admin.ModelAdmin):
-    inlines = [QuestionInline]
-
-    def call_me(self, obj):
-        return 'Callable in PollAdmin'
-
 class Novel(models.Model):
     name = models.CharField(max_length=40)
 
 class Chapter(models.Model):
     novel = models.ForeignKey(Novel)
 
-class ChapterInline(admin.TabularInline):
-    model = Chapter
-    readonly_fields=['call_me']
-
-    def call_me(self, obj):
-        return 'Callable in ChapterInline'
-
-class NovelAdmin(admin.ModelAdmin):
-    inlines = [ChapterInline]
-
-admin.site.register(Poll, PollAdmin)
-admin.site.register(Novel, NovelAdmin)
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
index 45ecb70..efa6cf6 100644
--- a/tests/regressiontests/admin_inlines/tests.py
+++ b/tests/regressiontests/admin_inlines/tests.py
@@ -3,18 +3,20 @@ from django.contrib.contenttypes.models import ContentType
 from django.test import TestCase
 
 # local test models
-from models import (Holder, Inner, InnerInline, Holder2, Inner2, Holder3,
+from models import (Holder, Inner, Holder2, Inner2, Holder3,
     Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child)
+from admin import InnerInline
 
 
 class TestInline(TestCase):
+    urls = "regressiontests.admin_inlines.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
         holder = Holder(dummy=13)
         holder.save()
         Inner(dummy=42, holder=holder).save()
-        self.change_url = '/test_admin/admin/admin_inlines/holder/%i/' % holder.id
+        self.change_url = '/admin/admin_inlines/holder/%i/' % holder.id
 
         result = self.client.login(username='super', password='secret')
         self.assertEqual(result, True)
@@ -36,13 +38,13 @@ class TestInline(TestCase):
         """Bug #13174."""
         holder = Holder.objects.create(dummy=42)
         inner = Inner.objects.create(holder=holder, dummy=42, readonly='')
-        response = self.client.get('/test_admin/admin/admin_inlines/holder/%i/'
+        response = self.client.get('/admin/admin_inlines/holder/%i/'
                                    % holder.id)
         self.assertContains(response, '<label>Inner readonly label:</label>')
 
     def test_many_to_many_inlines(self):
         "Autogenerated many-to-many inlines are displayed correctly (#13407)"
-        response = self.client.get('/test_admin/admin/admin_inlines/author/add/')
+        response = self.client.get('/admin/admin_inlines/author/add/')
         # The heading for the m2m inline block uses the right text
         self.assertContains(response, '<h2>Author-book relationships</h2>')
         # The "add another" label is correct
@@ -63,7 +65,7 @@ class TestInline(TestCase):
             'max_weight': 0,
             'shoppingweakness_set-0-item': item.id,
         }
-        response = self.client.post('/test_admin/admin/admin_inlines/fashionista/add/', data)
+        response = self.client.post('/admin/admin_inlines/fashionista/add/', data)
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
 
@@ -80,7 +82,7 @@ class TestInline(TestCase):
             'title_set-0-title1': 'a title',
             'title_set-0-title2': 'a different title',
         }
-        response = self.client.post('/test_admin/admin/admin_inlines/titlecollection/add/', data)
+        response = self.client.post('/admin/admin_inlines/titlecollection/add/', data)
         # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock.
         self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>')
 
@@ -88,14 +90,14 @@ class TestInline(TestCase):
         """Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable"""
         # Identically named callable isn't present in the parent ModelAdmin,
         # rendering of the add view shouldn't explode
-        response = self.client.get('/test_admin/admin/admin_inlines/novel/add/')
+        response = self.client.get('/admin/admin_inlines/novel/add/')
         self.assertEqual(response.status_code, 200)
         # View should have the child inlines section
         self.assertContains(response, '<div class="inline-group" id="chapter_set-group">')
 
     def test_callable_lookup(self):
         """Admin inline should invoke local callable when its name is listed in readonly_fields"""
-        response = self.client.get('/test_admin/admin/admin_inlines/poll/add/')
+        response = self.client.get('/admin/admin_inlines/poll/add/')
         self.assertEqual(response.status_code, 200)
         # Add parent object view should have the child inlines section
         self.assertContains(response, '<div class="inline-group" id="question_set-group">')
@@ -109,11 +111,12 @@ class TestInline(TestCase):
         using both the stacked and tabular layouts.
         Ref #8190.
         """
-        response = self.client.get('/test_admin/admin/admin_inlines/holder4/add/')
+        response = self.client.get('/admin/admin_inlines/holder4/add/')
         self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4)
         self.assertContains(response, '<img src="/static/admin/img/icon-unknown.gif" class="help help-tooltip" width="10" height="10" alt="(Awesome tabular help text is awesome.)" title="Awesome tabular help text is awesome." />', 1)
 
 class TestInlineMedia(TestCase):
+    urls = "regressiontests.admin_inlines.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -128,7 +131,7 @@ class TestInlineMedia(TestCase):
         holder = Holder(dummy=13)
         holder.save()
         Inner(dummy=42, holder=holder).save()
-        change_url = '/test_admin/admin/admin_inlines/holder/%i/' % holder.id
+        change_url = '/admin/admin_inlines/holder/%i/' % holder.id
         response = self.client.get(change_url)
         self.assertContains(response, 'my_awesome_admin_scripts.js')
 
@@ -136,7 +139,7 @@ class TestInlineMedia(TestCase):
         holder = Holder3(dummy=13)
         holder.save()
         Inner3(dummy=42, holder=holder).save()
-        change_url = '/test_admin/admin/admin_inlines/holder3/%i/' % holder.id
+        change_url = '/admin/admin_inlines/holder3/%i/' % holder.id
         response = self.client.get(change_url)
         self.assertContains(response, 'my_awesome_inline_scripts.js')
 
@@ -144,12 +147,13 @@ class TestInlineMedia(TestCase):
         holder = Holder2(dummy=13)
         holder.save()
         Inner2(dummy=42, holder=holder).save()
-        change_url = '/test_admin/admin/admin_inlines/holder2/%i/' % holder.id
+        change_url = '/admin/admin_inlines/holder2/%i/' % holder.id
         response = self.client.get(change_url)
         self.assertContains(response, 'my_awesome_admin_scripts.js')
         self.assertContains(response, 'my_awesome_inline_scripts.js')
 
 class TestInlineAdminForm(TestCase):
+    urls = "regressiontests.admin_inlines.urls"
 
     def test_immutable_content_type(self):
         """Regression for #9362
diff --git a/tests/regressiontests/admin_inlines/urls.py b/tests/regressiontests/admin_inlines/urls.py
new file mode 100644
index 0000000..1cbb496
--- /dev/null
+++ b/tests/regressiontests/admin_inlines/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls.defaults import *
+
+import admin
+
+urlpatterns = patterns('',
+    (r'^admin/', include(admin.site.urls)),
+)
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py
new file mode 100644
index 0000000..11b0b9e
--- /dev/null
+++ b/tests/regressiontests/admin_views/admin.py
@@ -0,0 +1,526 @@
+# -*- coding: utf-8 -*-
+import datetime
+import tempfile
+import os
+
+from django.contrib import admin
+from django.contrib.admin.views.main import ChangeList
+from django.forms.models import BaseModelFormSet
+from django.core.mail import EmailMessage
+
+from models import *
+
+
+def callable_year(dt_value):
+    return dt_value.year
+callable_year.admin_order_field = 'date'
+
+
+class ArticleInline(admin.TabularInline):
+    model = Article
+
+
+class ChapterInline(admin.TabularInline):
+    model = Chapter
+
+
+class ChapterXtra1Admin(admin.ModelAdmin):
+    list_filter = ('chap',
+                   'chap__title',
+                   'chap__book',
+                   'chap__book__name',
+                   'chap__book__promo',
+                   'chap__book__promo__name',)
+
+
+class ArticleAdmin(admin.ModelAdmin):
+    list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
+    list_filter = ('date', 'section')
+
+    def changelist_view(self, request):
+        "Test that extra_context works"
+        return super(ArticleAdmin, self).changelist_view(
+            request, extra_context={
+                'extra_var': 'Hello!'
+            }
+        )
+
+    def modeladmin_year(self, obj):
+        return obj.date.year
+    modeladmin_year.admin_order_field = 'date'
+    modeladmin_year.short_description = None
+
+    def delete_model(self, request, obj):
+        EmailMessage(
+            'Greetings from a deleted object',
+            'I hereby inform you that some user deleted me',
+            'from@example.com',
+            ['to@example.com']
+        ).send()
+        return super(ArticleAdmin, self).delete_model(request, obj)
+
+    def save_model(self, request, obj, form, change=True):
+        EmailMessage(
+            'Greetings from a created object',
+            'I hereby inform you that some user created me',
+            'from@example.com',
+            ['to@example.com']
+        ).send()
+        return super(ArticleAdmin, self).save_model(request, obj, form, change)
+
+
+class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
+    def has_change_permission(self, request, obj=None):
+        """ Only allow changing objects with even id number """
+        return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
+
+
+class CustomArticleAdmin(admin.ModelAdmin):
+    """
+    Tests various hooks for using custom templates and contexts.
+    """
+    change_list_template = 'custom_admin/change_list.html'
+    change_form_template = 'custom_admin/change_form.html'
+    add_form_template = 'custom_admin/add_form.html'
+    object_history_template = 'custom_admin/object_history.html'
+    delete_confirmation_template = 'custom_admin/delete_confirmation.html'
+    delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
+
+    def changelist_view(self, request):
+        "Test that extra_context works"
+        return super(CustomArticleAdmin, self).changelist_view(
+            request, extra_context={
+                'extra_var': 'Hello!'
+            }
+        )
+
+
+class ThingAdmin(admin.ModelAdmin):
+    list_filter = ('color__warm', 'color__value')
+
+
+class InquisitionAdmin(admin.ModelAdmin):
+    list_display = ('leader', 'country', 'expected')
+
+
+class SketchAdmin(admin.ModelAdmin):
+    raw_id_fields = ('inquisition',)
+
+
+class FabricAdmin(admin.ModelAdmin):
+    list_display = ('surface',)
+    list_filter = ('surface',)
+
+
+class BasePersonModelFormSet(BaseModelFormSet):
+    def clean(self):
+        for person_dict in self.cleaned_data:
+            person = person_dict.get('id')
+            alive = person_dict.get('alive')
+            if person and alive and person.name == "Grace Hopper":
+                raise forms.ValidationError("Grace is not a Zombie")
+
+
+class PersonAdmin(admin.ModelAdmin):
+    list_display = ('name', 'gender', 'alive')
+    list_editable = ('gender', 'alive')
+    list_filter = ('gender',)
+    search_fields = ('^name',)
+    save_as = True
+
+    def get_changelist_formset(self, request, **kwargs):
+        return super(PersonAdmin, self).get_changelist_formset(request,
+            formset=BasePersonModelFormSet, **kwargs)
+
+    def queryset(self, request):
+        # Order by a field that isn't in list display, to be able to test
+        # whether ordering is preserved.
+        return super(PersonAdmin, self).queryset(request).order_by('age')
+
+
+class FooAccount(Account):
+    """A service-specific account of type Foo."""
+    servicename = u'foo'
+
+
+class BarAccount(Account):
+    """A service-specific account of type Bar."""
+    servicename = u'bar'
+
+
+class FooAccountAdmin(admin.StackedInline):
+    model = FooAccount
+    extra = 1
+
+
+class BarAccountAdmin(admin.StackedInline):
+    model = BarAccount
+    extra = 1
+
+
+class PersonaAdmin(admin.ModelAdmin):
+    inlines = (
+        FooAccountAdmin,
+        BarAccountAdmin
+    )
+
+
+class SubscriberAdmin(admin.ModelAdmin):
+    actions = ['mail_admin']
+
+    def mail_admin(self, request, selected):
+        EmailMessage(
+            'Greetings from a ModelAdmin action',
+            'This is the test email from a admin action',
+            'from@example.com',
+            ['to@example.com']
+        ).send()
+
+
+def external_mail(modeladmin, request, selected):
+    EmailMessage(
+        'Greetings from a function action',
+        'This is the test email from a function action',
+        'from@example.com',
+        ['to@example.com']
+    ).send()
+external_mail.short_description = 'External mail (Another awesome action)'
+
+
+def redirect_to(modeladmin, request, selected):
+    from django.http import HttpResponseRedirect
+    return HttpResponseRedirect('/some-where-else/')
+redirect_to.short_description = 'Redirect to (Awesome action)'
+
+
+class ExternalSubscriberAdmin(admin.ModelAdmin):
+    actions = [redirect_to, external_mail]
+
+
+class Podcast(Media):
+    release_date = models.DateField()
+
+    class Meta:
+        ordering = ('release_date',) # overridden in PodcastAdmin
+
+
+class PodcastAdmin(admin.ModelAdmin):
+    list_display = ('name', 'release_date')
+    list_editable = ('release_date',)
+    date_hierarchy = 'release_date'
+    ordering = ('name',)
+
+
+class VodcastAdmin(admin.ModelAdmin):
+    list_display = ('name', 'released')
+    list_editable = ('released',)
+
+    ordering = ('name',)
+
+
+class ChildInline(admin.StackedInline):
+    model = Child
+
+
+class ParentAdmin(admin.ModelAdmin):
+    model = Parent
+    inlines = [ChildInline]
+
+    list_editable = ('name',)
+
+    def save_related(self, request, form, formsets, change):
+        super(ParentAdmin, self).save_related(request, form, formsets, change)
+        first_name, last_name = form.instance.name.split()
+        for child in form.instance.child_set.all():
+            if len(child.name.split()) < 2:
+                child.name = child.name + ' ' + last_name
+                child.save()
+
+
+class EmptyModelAdmin(admin.ModelAdmin):
+    def queryset(self, request):
+        return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
+
+
+class OldSubscriberAdmin(admin.ModelAdmin):
+    actions = None
+
+
+temp_storage = FileSystemStorage(tempfile.mkdtemp())
+UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
+
+
+class PictureInline(admin.TabularInline):
+    model = Picture
+    extra = 1
+
+
+class GalleryAdmin(admin.ModelAdmin):
+    inlines = [PictureInline]
+
+
+class PictureAdmin(admin.ModelAdmin):
+    pass
+
+
+class LanguageAdmin(admin.ModelAdmin):
+    list_display = ['iso', 'shortlist', 'english_name', 'name']
+    list_editable = ['shortlist']
+
+
+class RecommendationAdmin(admin.ModelAdmin):
+    search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
+
+
+class WidgetInline(admin.StackedInline):
+    model = Widget
+
+
+class DooHickeyInline(admin.StackedInline):
+    model = DooHickey
+
+
+class GrommetInline(admin.StackedInline):
+    model = Grommet
+
+
+class WhatsitInline(admin.StackedInline):
+    model = Whatsit
+
+
+class FancyDoodadInline(admin.StackedInline):
+    model = FancyDoodad
+
+
+class CategoryAdmin(admin.ModelAdmin):
+    list_display = ('id', 'collector', 'order')
+    list_editable = ('order',)
+
+
+class CategoryInline(admin.StackedInline):
+    model = Category
+
+
+class CollectorAdmin(admin.ModelAdmin):
+    inlines = [
+        WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
+        FancyDoodadInline, CategoryInline
+    ]
+
+
+class LinkInline(admin.TabularInline):
+    model = Link
+    extra = 1
+
+    readonly_fields = ("posted",)
+
+
+class SubPostInline(admin.TabularInline):
+    model = PrePopulatedSubPost
+
+    prepopulated_fields = {
+        'subslug' : ('subtitle',)
+    }
+
+    def get_readonly_fields(self, request, obj=None):
+        if obj and obj.published:
+            return ('subslug',)
+        return self.readonly_fields
+
+    def get_prepopulated_fields(self, request, obj=None):
+        if obj and obj.published:
+            return {}
+        return self.prepopulated_fields
+
+
+class PrePopulatedPostAdmin(admin.ModelAdmin):
+    list_display = ['title', 'slug']
+    prepopulated_fields = {
+        'slug' : ('title',)
+    }
+
+    inlines = [SubPostInline]
+
+    def get_readonly_fields(self, request, obj=None):
+        if obj and obj.published:
+            return ('slug',)
+        return self.readonly_fields
+
+    def get_prepopulated_fields(self, request, obj=None):
+        if obj and obj.published:
+            return {}
+        return self.prepopulated_fields
+
+
+class PostAdmin(admin.ModelAdmin):
+    list_display = ['title', 'public']
+    readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
+
+    inlines = [
+        LinkInline
+    ]
+
+    def coolness(self, instance):
+        if instance.pk:
+            return "%d amount of cool." % instance.pk
+        else:
+            return "Unkown coolness."
+
+    def value(self, instance):
+        return 1000
+    value.short_description = 'Value in $US'
+
+
+class CustomChangeList(ChangeList):
+    def get_query_set(self, request):
+        return self.root_query_set.filter(pk=9999) # Does not exist
+
+
+class GadgetAdmin(admin.ModelAdmin):
+    def get_changelist(self, request, **kwargs):
+        return CustomChangeList
+
+
+class PizzaAdmin(admin.ModelAdmin):
+    readonly_fields = ('toppings',)
+
+
+class WorkHourAdmin(admin.ModelAdmin):
+    list_display = ('datum', 'employee')
+    list_filter = ('employee',)
+
+
+class FoodDeliveryAdmin(admin.ModelAdmin):
+    list_display=('reference', 'driver', 'restaurant')
+    list_editable = ('driver', 'restaurant')
+
+
+class PaperAdmin(admin.ModelAdmin):
+    """
+    A ModelAdin with a custom queryset() method that uses only(), to test
+    verbose_name display in messages shown after adding Paper instances.
+    """
+
+    def queryset(self, request):
+        return super(PaperAdmin, self).queryset(request).only('title')
+
+
+class CoverLetterAdmin(admin.ModelAdmin):
+    """
+    A ModelAdin with a custom queryset() method that uses only(), to test
+    verbose_name display in messages shown after adding CoverLetter instances.
+    Note that the CoverLetter model defines a __unicode__ method.
+    """
+
+    def queryset(self, request):
+        return super(CoverLetterAdmin, self).queryset(request).defer('date_written')
+
+
+class StoryForm(forms.ModelForm):
+    class Meta:
+        widgets = {'title': forms.HiddenInput}
+
+
+class StoryAdmin(admin.ModelAdmin):
+    list_display = ('id', 'title', 'content')
+    list_display_links = ('title',) # 'id' not in list_display_links
+    list_editable = ('content', )
+    form = StoryForm
+    ordering = ["-pk"]
+
+
+class OtherStoryAdmin(admin.ModelAdmin):
+    list_display = ('id', 'title', 'content')
+    list_display_links = ('title', 'id') # 'id' in list_display_links
+    list_editable = ('content', )
+    ordering = ["-pk"]
+
+
+class ComplexSortedPersonAdmin(admin.ModelAdmin):
+    list_display = ('name', 'age', 'is_employee', 'colored_name')
+    ordering = ('name',)
+
+    def colored_name(self, obj):
+        return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name)
+    colored_name.allow_tags = True
+    colored_name.admin_order_field = 'name'
+
+
+class AlbumAdmin(admin.ModelAdmin):
+    list_filter = ['title']
+ 
+ 
+class WorkHourAdmin(admin.ModelAdmin):
+    list_display = ('datum', 'employee')
+    list_filter = ('employee',)
+
+
+site = admin.AdminSite(name="admin")
+site.register(Article, ArticleAdmin)
+site.register(CustomArticle, CustomArticleAdmin)
+site.register(Section, save_as=True, inlines=[ArticleInline])
+site.register(ModelWithStringPrimaryKey)
+site.register(Color)
+site.register(Thing, ThingAdmin)
+site.register(Actor)
+site.register(Inquisition, InquisitionAdmin)
+site.register(Sketch, SketchAdmin)
+site.register(Person, PersonAdmin)
+site.register(Persona, PersonaAdmin)
+site.register(Subscriber, SubscriberAdmin)
+site.register(ExternalSubscriber, ExternalSubscriberAdmin)
+site.register(OldSubscriber, OldSubscriberAdmin)
+site.register(Podcast, PodcastAdmin)
+site.register(Vodcast, VodcastAdmin)
+site.register(Parent, ParentAdmin)
+site.register(EmptyModel, EmptyModelAdmin)
+site.register(Fabric, FabricAdmin)
+site.register(Gallery, GalleryAdmin)
+site.register(Picture, PictureAdmin)
+site.register(Language, LanguageAdmin)
+site.register(Recommendation, RecommendationAdmin)
+site.register(Recommender)
+site.register(Collector, CollectorAdmin)
+site.register(Category, CategoryAdmin)
+site.register(Post, PostAdmin)
+site.register(Gadget, GadgetAdmin)
+site.register(Villain)
+site.register(SuperVillain)
+site.register(Plot)
+site.register(PlotDetails)
+site.register(CyclicOne)
+site.register(CyclicTwo)
+site.register(WorkHour, WorkHourAdmin)
+site.register(Reservation)
+site.register(FoodDelivery, FoodDeliveryAdmin)
+site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
+site.register(Paper, PaperAdmin)
+site.register(CoverLetter, CoverLetterAdmin)
+site.register(Story, StoryAdmin)
+site.register(OtherStory, OtherStoryAdmin)
+
+# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
+# That way we cover all four cases:
+#     related ForeignKey object registered in admin
+#     related ForeignKey object not registered in admin
+#     related OneToOne object registered in admin
+#     related OneToOne object not registered in admin
+# when deleting Book so as exercise all four troublesome (w.r.t escaping
+# and calling force_unicode to avoid problems on Python 2.3) paths through
+# contrib.admin.util's get_deleted_objects function.
+site.register(Book, inlines=[ChapterInline])
+site.register(Promo)
+site.register(ChapterXtra1, ChapterXtra1Admin)
+site.register(Pizza, PizzaAdmin)
+site.register(Topping)
+site.register(Album, AlbumAdmin)
+site.register(Question)
+site.register(Answer)
+site.register(PrePopulatedPost, PrePopulatedPostAdmin)
+site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
+
+# Register core models we need in our tests
+from django.contrib.auth.models import User, Group
+from django.contrib.auth.admin import UserAdmin, GroupAdmin
+site.register(User, UserAdmin)
+site.register(Group, GroupAdmin)
diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py
index 760e93f..a696e9f 100644
--- a/tests/regressiontests/admin_views/customadmin.py
+++ b/tests/regressiontests/admin_views/customadmin.py
@@ -5,7 +5,7 @@ from django.conf.urls import patterns
 from django.contrib import admin
 from django.http import HttpResponse
 
-import models, forms
+import models, forms, admin as base_admin
 
 class Admin2(admin.AdminSite):
     login_form = forms.CustomAdminAuthenticationForm
@@ -29,8 +29,8 @@ class Admin2(admin.AdminSite):
 
 site = Admin2(name="admin2")
 
-site.register(models.Article, models.ArticleAdmin)
-site.register(models.Section, inlines=[models.ArticleInline])
-site.register(models.Thing, models.ThingAdmin)
-site.register(models.Fabric, models.FabricAdmin)
-site.register(models.ChapterXtra1, models.ChapterXtra1Admin)
+site.register(models.Article, base_admin.ArticleAdmin)
+site.register(models.Section, inlines=[base_admin.ArticleInline])
+site.register(models.Thing, base_admin.ThingAdmin)
+site.register(models.Fabric, base_admin.FabricAdmin)
+site.register(models.ChapterXtra1, base_admin.ChapterXtra1Admin)
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 8dc61e3..bb8d026 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -3,17 +3,14 @@ import datetime
 import tempfile
 import os
 
-from django.contrib import admin
 from django.core.files.storage import FileSystemStorage
-from django.contrib.admin.views.main import ChangeList
-from django.core.mail import EmailMessage
 from django.db import models
 from django import forms
-from django.forms.models import BaseModelFormSet
 from django.contrib.auth.models import User
 from django.contrib.contenttypes import generic
 from django.contrib.contenttypes.models import ContentType
 
+
 class Section(models.Model):
     """
     A simple section that links to articles, to test linking to related items
@@ -21,6 +18,7 @@ class Section(models.Model):
     """
     name = models.CharField(max_length=100)
 
+
 class Article(models.Model):
     """
     A simple article to test admin views. Test backwards compatibility.
@@ -38,6 +36,7 @@ class Article(models.Model):
     model_year.admin_order_field = 'date'
     model_year.short_description = ''
 
+
 class Book(models.Model):
     """
     A simple book that has chapters.
@@ -47,6 +46,7 @@ class Book(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Promo(models.Model):
     name = models.CharField(max_length=100, verbose_name=u'¿Name?')
     book = models.ForeignKey(Book)
@@ -54,6 +54,7 @@ class Promo(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Chapter(models.Model):
     title = models.CharField(max_length=100, verbose_name=u'¿Title?')
     content = models.TextField()
@@ -66,6 +67,7 @@ class Chapter(models.Model):
         # Use a utf-8 bytestring to ensure it works (see #11710)
         verbose_name = '¿Chapter?'
 
+
 class ChapterXtra1(models.Model):
     chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
     xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
@@ -73,6 +75,7 @@ class ChapterXtra1(models.Model):
     def __unicode__(self):
         return u'¿Xtra1: %s' % self.xtra
 
+
 class ChapterXtra2(models.Model):
     chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?')
     xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?')
@@ -80,89 +83,15 @@ class ChapterXtra2(models.Model):
     def __unicode__(self):
         return u'¿Xtra2: %s' % self.xtra
 
-def callable_year(dt_value):
-    return dt_value.year
-callable_year.admin_order_field = 'date'
-
-class ArticleInline(admin.TabularInline):
-    model = Article
-
-class ChapterInline(admin.TabularInline):
-    model = Chapter
-
-class ChapterXtra1Admin(admin.ModelAdmin):
-    list_filter = ('chap',
-                   'chap__title',
-                   'chap__book',
-                   'chap__book__name',
-                   'chap__book__promo',
-                   'chap__book__promo__name',)
-
-class ArticleAdmin(admin.ModelAdmin):
-    list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
-    list_filter = ('date', 'section')
-
-    def changelist_view(self, request):
-        "Test that extra_context works"
-        return super(ArticleAdmin, self).changelist_view(
-            request, extra_context={
-                'extra_var': 'Hello!'
-            }
-        )
-
-    def modeladmin_year(self, obj):
-        return obj.date.year
-    modeladmin_year.admin_order_field = 'date'
-    modeladmin_year.short_description = None
-
-    def delete_model(self, request, obj):
-        EmailMessage(
-            'Greetings from a deleted object',
-            'I hereby inform you that some user deleted me',
-            'from@example.com',
-            ['to@example.com']
-        ).send()
-        return super(ArticleAdmin, self).delete_model(request, obj)
-
-    def save_model(self, request, obj, form, change=True):
-        EmailMessage(
-            'Greetings from a created object',
-            'I hereby inform you that some user created me',
-            'from@example.com',
-            ['to@example.com']
-        ).send()
-        return super(ArticleAdmin, self).save_model(request, obj, form, change)
 
 class RowLevelChangePermissionModel(models.Model):
     name = models.CharField(max_length=100, blank=True)
 
-class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
-    def has_change_permission(self, request, obj=None):
-        """ Only allow changing objects with even id number """
-        return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
 
 class CustomArticle(models.Model):
     content = models.TextField()
     date = models.DateTimeField()
 
-class CustomArticleAdmin(admin.ModelAdmin):
-    """
-    Tests various hooks for using custom templates and contexts.
-    """
-    change_list_template = 'custom_admin/change_list.html'
-    change_form_template = 'custom_admin/change_form.html'
-    add_form_template = 'custom_admin/add_form.html'
-    object_history_template = 'custom_admin/object_history.html'
-    delete_confirmation_template = 'custom_admin/delete_confirmation.html'
-    delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'
-
-    def changelist_view(self, request):
-        "Test that extra_context works"
-        return super(CustomArticleAdmin, self).changelist_view(
-            request, extra_context={
-                'extra_var': 'Hello!'
-            }
-        )
 
 class ModelWithStringPrimaryKey(models.Model):
     id = models.CharField(max_length=255, primary_key=True)
@@ -170,20 +99,20 @@ class ModelWithStringPrimaryKey(models.Model):
     def __unicode__(self):
         return self.id
 
+
 class Color(models.Model):
     value = models.CharField(max_length=10)
     warm = models.BooleanField()
     def __unicode__(self):
         return self.value
 
+
 class Thing(models.Model):
     title = models.CharField(max_length=20)
     color = models.ForeignKey(Color, limit_choices_to={'warm': True})
     def __unicode__(self):
         return self.title
 
-class ThingAdmin(admin.ModelAdmin):
-    list_filter = ('color__warm', 'color__value')
 
 class Actor(models.Model):
     name = models.CharField(max_length=50)
@@ -191,6 +120,7 @@ class Actor(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Inquisition(models.Model):
     expected = models.BooleanField()
     leader = models.ForeignKey(Actor)
@@ -199,8 +129,6 @@ class Inquisition(models.Model):
     def __unicode__(self):
         return u"by %s from %s" % (self.leader, self.country)
 
-class InquisitionAdmin(admin.ModelAdmin):
-    list_display = ('leader', 'country', 'expected')
 
 class Sketch(models.Model):
     title = models.CharField(max_length=100)
@@ -212,8 +140,6 @@ class Sketch(models.Model):
     def __unicode__(self):
         return self.title
 
-class SketchAdmin(admin.ModelAdmin):
-    raw_id_fields = ('inquisition',)
 
 class Fabric(models.Model):
     NG_CHOICES = (
@@ -226,9 +152,6 @@ class Fabric(models.Model):
     )
     surface = models.CharField(max_length=20, choices=NG_CHOICES)
 
-class FabricAdmin(admin.ModelAdmin):
-    list_display = ('surface',)
-    list_filter = ('surface',)
 
 class Person(models.Model):
     GENDER_CHOICES = (
@@ -243,30 +166,6 @@ class Person(models.Model):
     def __unicode__(self):
         return self.name
 
-class BasePersonModelFormSet(BaseModelFormSet):
-    def clean(self):
-        for person_dict in self.cleaned_data:
-            person = person_dict.get('id')
-            alive = person_dict.get('alive')
-            if person and alive and person.name == "Grace Hopper":
-                raise forms.ValidationError("Grace is not a Zombie")
-
-class PersonAdmin(admin.ModelAdmin):
-    list_display = ('name', 'gender', 'alive')
-    list_editable = ('gender', 'alive')
-    list_filter = ('gender',)
-    search_fields = ('^name',)
-    save_as = True
-
-    def get_changelist_formset(self, request, **kwargs):
-        return super(PersonAdmin, self).get_changelist_formset(request,
-            formset=BasePersonModelFormSet, **kwargs)
-
-    def queryset(self, request):
-        # Order by a field that isn't in list display, to be able to test
-        # whether ordering is preserved.
-        return super(PersonAdmin, self).queryset(request).order_by('age')
-
 
 class Persona(models.Model):
     """
@@ -277,6 +176,7 @@ class Persona(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Account(models.Model):
     """
     A simple, generic account encapsulating the information shared by all
@@ -289,27 +189,16 @@ class Account(models.Model):
     def __unicode__(self):
         return "%s: %s" % (self.servicename, self.username)
 
+
 class FooAccount(Account):
     """A service-specific account of type Foo."""
     servicename = u'foo'
 
+
 class BarAccount(Account):
     """A service-specific account of type Bar."""
     servicename = u'bar'
 
-class FooAccountAdmin(admin.StackedInline):
-    model = FooAccount
-    extra = 1
-
-class BarAccountAdmin(admin.StackedInline):
-    model = BarAccount
-    extra = 1
-
-class PersonaAdmin(admin.ModelAdmin):
-    inlines = (
-        FooAccountAdmin,
-        BarAccountAdmin
-    )
 
 class Subscriber(models.Model):
     name = models.CharField(blank=False, max_length=80)
@@ -318,120 +207,58 @@ class Subscriber(models.Model):
     def __unicode__(self):
         return "%s (%s)" % (self.name, self.email)
 
-class SubscriberAdmin(admin.ModelAdmin):
-    actions = ['mail_admin']
-
-    def mail_admin(self, request, selected):
-        EmailMessage(
-            'Greetings from a ModelAdmin action',
-            'This is the test email from a admin action',
-            'from@example.com',
-            ['to@example.com']
-        ).send()
 
 class ExternalSubscriber(Subscriber):
     pass
 
+
 class OldSubscriber(Subscriber):
     pass
 
-def external_mail(modeladmin, request, selected):
-    EmailMessage(
-        'Greetings from a function action',
-        'This is the test email from a function action',
-        'from@example.com',
-        ['to@example.com']
-    ).send()
-external_mail.short_description = 'External mail (Another awesome action)'
-
-def redirect_to(modeladmin, request, selected):
-    from django.http import HttpResponseRedirect
-    return HttpResponseRedirect('/some-where-else/')
-redirect_to.short_description = 'Redirect to (Awesome action)'
-
-class ExternalSubscriberAdmin(admin.ModelAdmin):
-    actions = [redirect_to, external_mail]
 
 class Media(models.Model):
     name = models.CharField(max_length=60)
 
+
 class Podcast(Media):
     release_date = models.DateField()
 
     class Meta:
         ordering = ('release_date',) # overridden in PodcastAdmin
 
-class PodcastAdmin(admin.ModelAdmin):
-    list_display = ('name', 'release_date')
-    list_editable = ('release_date',)
-    date_hierarchy = 'release_date'
-    ordering = ('name',)
 
 class Vodcast(Media):
     media = models.OneToOneField(Media, primary_key=True, parent_link=True)
     released = models.BooleanField(default=False)
 
-class VodcastAdmin(admin.ModelAdmin):
-    list_display = ('name', 'released')
-    list_editable = ('released',)
-
-    ordering = ('name',)
 
 class Parent(models.Model):
     name = models.CharField(max_length=128)
 
+
 class Child(models.Model):
     parent = models.ForeignKey(Parent, editable=False)
     name = models.CharField(max_length=30, blank=True)
 
-class ChildInline(admin.StackedInline):
-    model = Child
-
-class ParentAdmin(admin.ModelAdmin):
-    model = Parent
-    inlines = [ChildInline]
-
-    list_editable = ('name',)
-
-    def save_related(self, request, form, formsets, change):
-        super(ParentAdmin, self).save_related(request, form, formsets, change)
-        first_name, last_name = form.instance.name.split()
-        for child in form.instance.child_set.all():
-            if len(child.name.split()) < 2:
-                child.name = child.name + ' ' + last_name
-                child.save()
 
 class EmptyModel(models.Model):
     def __unicode__(self):
         return "Primary key = %s" % self.id
 
-class EmptyModelAdmin(admin.ModelAdmin):
-    def queryset(self, request):
-        return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)
-
-class OldSubscriberAdmin(admin.ModelAdmin):
-    actions = None
 
 temp_storage = FileSystemStorage(tempfile.mkdtemp())
 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload')
 
+
 class Gallery(models.Model):
     name = models.CharField(max_length=100)
 
+
 class Picture(models.Model):
     name = models.CharField(max_length=100)
     image = models.FileField(storage=temp_storage, upload_to='test_upload')
     gallery = models.ForeignKey(Gallery, related_name="pictures")
 
-class PictureInline(admin.TabularInline):
-    model = Picture
-    extra = 1
-
-class GalleryAdmin(admin.ModelAdmin):
-    inlines = [PictureInline]
-
-class PictureAdmin(admin.ModelAdmin):
-    pass
 
 class Language(models.Model):
     iso = models.CharField(max_length=5, primary_key=True)
@@ -442,70 +269,60 @@ class Language(models.Model):
     class Meta:
         ordering = ('iso',)
 
-class LanguageAdmin(admin.ModelAdmin):
-    list_display = ['iso', 'shortlist', 'english_name', 'name']
-    list_editable = ['shortlist']
 
 # a base class for Recommender and Recommendation
 class Title(models.Model):
     pass
 
+
 class TitleTranslation(models.Model):
     title = models.ForeignKey(Title)
     text = models.CharField(max_length=100)
 
+
 class Recommender(Title):
     pass
 
+
 class Recommendation(Title):
     recommender = models.ForeignKey(Recommender)
 
-class RecommendationAdmin(admin.ModelAdmin):
-    search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)
 
 class Collector(models.Model):
     name = models.CharField(max_length=100)
 
+
 class Widget(models.Model):
     owner = models.ForeignKey(Collector)
     name = models.CharField(max_length=100)
 
+
 class DooHickey(models.Model):
     code = models.CharField(max_length=10, primary_key=True)
     owner = models.ForeignKey(Collector)
     name = models.CharField(max_length=100)
 
+
 class Grommet(models.Model):
     code = models.AutoField(primary_key=True)
     owner = models.ForeignKey(Collector)
     name = models.CharField(max_length=100)
 
+
 class Whatsit(models.Model):
     index = models.IntegerField(primary_key=True)
     owner = models.ForeignKey(Collector)
     name = models.CharField(max_length=100)
 
+
 class Doodad(models.Model):
     name = models.CharField(max_length=100)
 
+
 class FancyDoodad(Doodad):
     owner = models.ForeignKey(Collector)
     expensive = models.BooleanField(default=True)
 
-class WidgetInline(admin.StackedInline):
-    model = Widget
-
-class DooHickeyInline(admin.StackedInline):
-    model = DooHickey
-
-class GrommetInline(admin.StackedInline):
-    model = Grommet
-
-class WhatsitInline(admin.StackedInline):
-    model = Whatsit
-
-class FancyDoodadInline(admin.StackedInline):
-    model = FancyDoodad
 
 class Category(models.Model):
     collector = models.ForeignKey(Collector)
@@ -517,18 +334,6 @@ class Category(models.Model):
     def __unicode__(self):
         return u'%s:o%s' % (self.id, self.order)
 
-class CategoryAdmin(admin.ModelAdmin):
-    list_display = ('id', 'collector', 'order')
-    list_editable = ('order',)
-
-class CategoryInline(admin.StackedInline):
-    model = Category
-
-class CollectorAdmin(admin.ModelAdmin):
-    inlines = [
-        WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,
-        FancyDoodadInline, CategoryInline
-    ]
 
 class Link(models.Model):
     posted = models.DateField(
@@ -538,57 +343,17 @@ class Link(models.Model):
     post = models.ForeignKey("Post")
 
 
-class LinkInline(admin.TabularInline):
-    model = Link
-    extra = 1
-
-    readonly_fields = ("posted",)
-
-
 class PrePopulatedPost(models.Model):
     title = models.CharField(max_length=100)
     published = models.BooleanField()
     slug = models.SlugField()
 
+
 class PrePopulatedSubPost(models.Model):
     post = models.ForeignKey(PrePopulatedPost)
     subtitle = models.CharField(max_length=100)
     subslug = models.SlugField()
 
-class SubPostInline(admin.TabularInline):
-    model = PrePopulatedSubPost
-
-    prepopulated_fields = {
-        'subslug' : ('subtitle',)
-    }
-
-    def get_readonly_fields(self, request, obj=None):
-        if obj and obj.published:
-            return ('subslug',)
-        return self.readonly_fields
-
-    def get_prepopulated_fields(self, request, obj=None):
-        if obj and obj.published:
-            return {}
-        return self.prepopulated_fields
-
-class PrePopulatedPostAdmin(admin.ModelAdmin):
-    list_display = ['title', 'slug']
-    prepopulated_fields = {
-        'slug' : ('title',)
-    }
-
-    inlines = [SubPostInline]
-
-    def get_readonly_fields(self, request, obj=None):
-        if obj and obj.published:
-            return ('slug',)
-        return self.readonly_fields
-
-    def get_prepopulated_fields(self, request, obj=None):
-        if obj and obj.published:
-            return {}
-        return self.prepopulated_fields
 
 class Post(models.Model):
     title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ŠĐĆŽćžšđ)")
@@ -602,23 +367,6 @@ class Post(models.Model):
     def awesomeness_level(self):
         return "Very awesome."
 
-class PostAdmin(admin.ModelAdmin):
-    list_display = ['title', 'public']
-    readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")
-
-    inlines = [
-        LinkInline
-    ]
-
-    def coolness(self, instance):
-        if instance.pk:
-            return "%d amount of cool." % instance.pk
-        else:
-            return "Unkown coolness."
-
-    def value(self, instance):
-        return 1000
-    value.short_description = 'Value in $US'
 
 class Gadget(models.Model):
     name = models.CharField(max_length=100)
@@ -626,13 +374,6 @@ class Gadget(models.Model):
     def __unicode__(self):
         return self.name
 
-class CustomChangeList(ChangeList):
-    def get_query_set(self, request):
-        return self.root_query_set.filter(pk=9999) # Does not exist
-
-class GadgetAdmin(admin.ModelAdmin):
-    def get_changelist(self, request, **kwargs):
-        return CustomChangeList
 
 class Villain(models.Model):
     name = models.CharField(max_length=100)
@@ -640,9 +381,11 @@ class Villain(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class SuperVillain(Villain):
     pass
 
+
 class FunkyTag(models.Model):
     "Because we all know there's only one real use case for GFKs."
     name = models.CharField(max_length=25)
@@ -653,6 +396,7 @@ class FunkyTag(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Plot(models.Model):
     name = models.CharField(max_length=100)
     team_leader = models.ForeignKey(Villain, related_name='lead_plots')
@@ -662,6 +406,7 @@ class Plot(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class PlotDetails(models.Model):
     details = models.CharField(max_length=100)
     plot = models.OneToOneField(Plot)
@@ -669,6 +414,7 @@ class PlotDetails(models.Model):
     def __unicode__(self):
         return self.details
 
+
 class SecretHideout(models.Model):
     """ Secret! Not registered with the admin! """
     location = models.CharField(max_length=100)
@@ -677,6 +423,7 @@ class SecretHideout(models.Model):
     def __unicode__(self):
         return self.location
 
+
 class SuperSecretHideout(models.Model):
     """ Secret! Not registered with the admin! """
     location = models.CharField(max_length=100)
@@ -685,6 +432,7 @@ class SuperSecretHideout(models.Model):
     def __unicode__(self):
         return self.location
 
+
 class CyclicOne(models.Model):
     name = models.CharField(max_length=25)
     two = models.ForeignKey('CyclicTwo')
@@ -692,6 +440,7 @@ class CyclicOne(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class CyclicTwo(models.Model):
     name = models.CharField(max_length=25)
     one = models.ForeignKey(CyclicOne)
@@ -699,37 +448,34 @@ class CyclicTwo(models.Model):
     def __unicode__(self):
         return self.name
 
+
 class Topping(models.Model):
     name = models.CharField(max_length=20)
 
+
 class Pizza(models.Model):
     name = models.CharField(max_length=20)
     toppings = models.ManyToManyField('Topping')
 
-class PizzaAdmin(admin.ModelAdmin):
-    readonly_fields = ('toppings',)
 
 class Album(models.Model):
     owner = models.ForeignKey(User)
     title = models.CharField(max_length=30)
 
-class AlbumAdmin(admin.ModelAdmin):
-    list_filter = ['title']
 
 class Employee(Person):
     code = models.CharField(max_length=20)
 
+
 class WorkHour(models.Model):
     datum = models.DateField()
     employee = models.ForeignKey(Employee)
 
-class WorkHourAdmin(admin.ModelAdmin):
-    list_display = ('datum', 'employee')
-    list_filter = ('employee',)
 
 class Question(models.Model):
     question = models.CharField(max_length=20)
 
+
 class Answer(models.Model):
     question = models.ForeignKey(Question, on_delete=models.PROTECT)
     answer = models.CharField(max_length=20)
@@ -737,6 +483,7 @@ class Answer(models.Model):
     def __unicode__(self):
         return self.answer
 
+
 class Reservation(models.Model):
     start_date = models.DateTimeField()
     price = models.IntegerField()
@@ -753,6 +500,7 @@ RESTAURANT_CHOICES = (
     (u'pizza', u'Pizza Mama'),
 )
 
+
 class FoodDelivery(models.Model):
     reference = models.CharField(max_length=100)
     driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True)
@@ -761,14 +509,12 @@ class FoodDelivery(models.Model):
     class Meta:
         unique_together = (("driver", "restaurant"),)
 
-class FoodDeliveryAdmin(admin.ModelAdmin):
-    list_display=('reference', 'driver', 'restaurant')
-    list_editable = ('driver', 'restaurant')
 
 class Paper(models.Model):
     title = models.CharField(max_length=30)
     author = models.CharField(max_length=30, blank=True, null=True)
 
+
 class CoverLetter(models.Model):
     author = models.CharField(max_length=30)
     date_written = models.DateField(null=True, blank=True)
@@ -776,123 +522,19 @@ class CoverLetter(models.Model):
     def __unicode__(self):
         return self.author
 
-class PaperAdmin(admin.ModelAdmin):
-    """
-    A ModelAdin with a custom queryset() method that uses only(), to test
-    verbose_name display in messages shown after adding Paper instances.
-    """
-
-    def queryset(self, request):
-        return super(PaperAdmin, self).queryset(request).only('title')
-
-class CoverLetterAdmin(admin.ModelAdmin):
-    """
-    A ModelAdin with a custom queryset() method that uses only(), to test
-    verbose_name display in messages shown after adding CoverLetter instances.
-    Note that the CoverLetter model defines a __unicode__ method.
-    """
-
-    def queryset(self, request):
-        return super(CoverLetterAdmin, self).queryset(request).defer('date_written')
 
 class Story(models.Model):
     title = models.CharField(max_length=100)
     content = models.TextField()
 
-class StoryForm(forms.ModelForm):
-    class Meta:
-        widgets = {'title': forms.HiddenInput}
-
-class StoryAdmin(admin.ModelAdmin):
-    list_display = ('id', 'title', 'content')
-    list_display_links = ('title',) # 'id' not in list_display_links
-    list_editable = ('content', )
-    form = StoryForm
-    ordering = ["-pk"]
 
 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', )
-    ordering = ["-pk"]
 
 class ComplexSortedPerson(models.Model):
     name = models.CharField(max_length=100)
     age = models.PositiveIntegerField()
     is_employee = models.NullBooleanField()
 
-class ComplexSortedPersonAdmin(admin.ModelAdmin):
-    list_display = ('name', 'age', 'is_employee', 'colored_name')
-    ordering = ('name',)
-
-    def colored_name(self, obj):
-        return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name)
-    colored_name.allow_tags = True
-    colored_name.admin_order_field = 'name'
-
-admin.site.register(Article, ArticleAdmin)
-admin.site.register(CustomArticle, CustomArticleAdmin)
-admin.site.register(Section, save_as=True, inlines=[ArticleInline])
-admin.site.register(ModelWithStringPrimaryKey)
-admin.site.register(Color)
-admin.site.register(Thing, ThingAdmin)
-admin.site.register(Actor)
-admin.site.register(Inquisition, InquisitionAdmin)
-admin.site.register(Sketch, SketchAdmin)
-admin.site.register(Person, PersonAdmin)
-admin.site.register(Persona, PersonaAdmin)
-admin.site.register(Subscriber, SubscriberAdmin)
-admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)
-admin.site.register(OldSubscriber, OldSubscriberAdmin)
-admin.site.register(Podcast, PodcastAdmin)
-admin.site.register(Vodcast, VodcastAdmin)
-admin.site.register(Parent, ParentAdmin)
-admin.site.register(EmptyModel, EmptyModelAdmin)
-admin.site.register(Fabric, FabricAdmin)
-admin.site.register(Gallery, GalleryAdmin)
-admin.site.register(Picture, PictureAdmin)
-admin.site.register(Language, LanguageAdmin)
-admin.site.register(Recommendation, RecommendationAdmin)
-admin.site.register(Recommender)
-admin.site.register(Collector, CollectorAdmin)
-admin.site.register(Category, CategoryAdmin)
-admin.site.register(Post, PostAdmin)
-admin.site.register(Gadget, GadgetAdmin)
-admin.site.register(Villain)
-admin.site.register(SuperVillain)
-admin.site.register(Plot)
-admin.site.register(PlotDetails)
-admin.site.register(CyclicOne)
-admin.site.register(CyclicTwo)
-admin.site.register(WorkHour, WorkHourAdmin)
-admin.site.register(Reservation)
-admin.site.register(FoodDelivery, FoodDeliveryAdmin)
-admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
-admin.site.register(Paper, PaperAdmin)
-admin.site.register(CoverLetter, CoverLetterAdmin)
-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:
-#     related ForeignKey object registered in admin
-#     related ForeignKey object not registered in admin
-#     related OneToOne object registered in admin
-#     related OneToOne object not registered in admin
-# when deleting Book so as exercise all four troublesome (w.r.t escaping
-# and calling force_unicode to avoid problems on Python 2.3) paths through
-# contrib.admin.util's get_deleted_objects function.
-admin.site.register(Book, inlines=[ChapterInline])
-admin.site.register(Promo)
-admin.site.register(ChapterXtra1, ChapterXtra1Admin)
-admin.site.register(Pizza, PizzaAdmin)
-admin.site.register(Topping)
-admin.site.register(Album, AlbumAdmin)
-admin.site.register(Question)
-admin.site.register(Answer)
-admin.site.register(PrePopulatedPost, PrePopulatedPostAdmin)
-admin.site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index 22b65a6..d4b2715 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -32,7 +32,7 @@ from django.utils import unittest
 
 # local test models
 from models import (Article, BarAccount, CustomArticle, EmptyModel,
-    FooAccount, Gallery, PersonAdmin, ModelWithStringPrimaryKey,
+    FooAccount, Gallery, ModelWithStringPrimaryKey,
     Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
     Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
     Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
@@ -40,6 +40,8 @@ from models import (Article, BarAccount, CustomArticle, EmptyModel,
     RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory,
     ComplexSortedPerson, Parent, Child)
 
+from admin import PersonAdmin
+
 
 class AdminViewBasicTest(TestCase):
     fixtures = ['admin-views-users.xml', 'admin-views-colors.xml',
@@ -50,6 +52,8 @@ class AdminViewBasicTest(TestCase):
     # this test case and changing urlbit.
     urlbit = 'admin'
 
+    urls = "regressiontests.admin_views.urls"
+
     def setUp(self):
         self.old_USE_I18N = settings.USE_I18N
         self.old_USE_L10N = settings.USE_L10N
@@ -542,6 +546,8 @@ class AdminViewBasicTest(TestCase):
             self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model")
 
 class AdminJavaScriptTest(AdminViewBasicTest):
+    urls = "regressiontests.admin_views.urls"
+
     def testSingleWidgetFirsFieldFocus(self):
         """
         JavaScript-assisted auto-focus on first field.
@@ -565,6 +571,7 @@ class AdminJavaScriptTest(AdminViewBasicTest):
 
 
 class SaveAsTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml','admin-views-person.xml']
 
     def setUp(self):
@@ -590,9 +597,10 @@ class SaveAsTests(TestCase):
         self.assertTrue(response.context['save_as'])
         post_data = {'_saveasnew':'', 'name':'John M', 'gender':3, 'alive':'checked'}
         response = self.client.post('/test_admin/admin/admin_views/person/1/', post_data)
-        self.assertEqual(response.context['form_url'], '../add/')
+        self.assertEqual(response.context['form_url'], '/test_admin/admin/admin_views/person/add/')
 
 class CustomModelAdminTest(AdminViewBasicTest):
+    urls = "regressiontests.admin_views.urls"
     urlbit = "admin2"
 
     def testCustomAdminSiteLoginForm(self):
@@ -654,6 +662,7 @@ def get_perm(Model, perm):
 class AdminViewPermissionsTest(TestCase):
     """Tests for Admin Views Permissions."""
 
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -835,7 +844,7 @@ class AdminViewPermissionsTest(TestCase):
         self.client.post('/test_admin/admin/', self.adduser_login)
         addpage = self.client.get('/test_admin/admin/admin_views/article/add/')
         self.assertEqual(addpage.status_code, 200)
-        change_list_link = '<a href="../">Articles</a> &rsaquo;'
+        change_list_link = '&rsaquo; <a href="/test_admin/admin/admin_views/article/">Articles</a>'
         self.assertFalse(change_list_link in addpage.content,
                     'User restricted to add permission is given link to change list view in breadcrumbs.')
         post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict)
@@ -1055,6 +1064,7 @@ class AdminViewPermissionsTest(TestCase):
 
 
 class AdminViewDeletedObjectsTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'deleted-objects.xml']
 
     def setUp(self):
@@ -1170,6 +1180,7 @@ class AdminViewDeletedObjectsTest(TestCase):
         self.assertContains(response, should_contain)
 
 class AdminViewStringPrimaryKeyTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'string-primary-key.xml']
 
     def __init__(self, *args):
@@ -1261,6 +1272,7 @@ class AdminViewStringPrimaryKeyTest(TestCase):
 
 
 class SecureViewTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -1418,6 +1430,7 @@ class SecureViewTests(TestCase):
         self.assertEqual(response['Location'], 'http://example.com/users/super/')
 
 class AdminViewUnicodeTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-unicode.xml']
 
     def setUp(self):
@@ -1471,6 +1484,7 @@ class AdminViewUnicodeTest(TestCase):
 
 
 class AdminViewListEditable(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'admin-views-person.xml']
 
     def setUp(self):
@@ -1827,6 +1841,7 @@ class AdminViewListEditable(TestCase):
 
 
 class AdminSearchTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users', 'multiple-child-classes',
                 'admin-views-person']
 
@@ -1873,6 +1888,7 @@ class AdminSearchTest(TestCase):
 
 
 class AdminInheritedInlinesTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml',]
 
     def setUp(self):
@@ -1958,6 +1974,7 @@ class AdminInheritedInlinesTest(TestCase):
         self.assertEqual(Persona.objects.all()[0].accounts.count(), 2)
 
 class AdminActionsTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
 
     def setUp(self):
@@ -2179,6 +2196,7 @@ class AdminActionsTest(TestCase):
 
 
 class TestCustomChangeList(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
     urlbit = 'admin'
 
@@ -2206,6 +2224,7 @@ class TestCustomChangeList(TestCase):
 
 
 class TestInlineNotEditable(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2223,6 +2242,7 @@ class TestInlineNotEditable(TestCase):
         self.assertEqual(response.status_code, 200)
 
 class AdminCustomQuerysetTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2277,6 +2297,7 @@ class AdminCustomQuerysetTest(TestCase):
         self.assertContains(response, '<li class="info">The cover letter &quot;John Doe II&quot; was changed successfully.</li>')
 
 class AdminInlineFileUploadTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'admin-views-actions.xml']
     urlbit = 'admin'
 
@@ -2322,6 +2343,7 @@ class AdminInlineFileUploadTest(TestCase):
 
 
 class AdminInlineTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2639,6 +2661,7 @@ class AdminInlineTests(TestCase):
 
 
 class NeverCacheTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml']
 
     def setUp(self):
@@ -2711,6 +2734,7 @@ class NeverCacheTests(TestCase):
 
 
 class PrePopulatedTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2735,6 +2759,7 @@ class PrePopulatedTest(TestCase):
         self.assertNotContains(response, "id: '#id_prepopulatedsubpost_set-0-subslug',")
 
 class ReadonlyTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2802,6 +2827,7 @@ class ReadonlyTest(TestCase):
 
 
 class RawIdFieldsTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2837,6 +2863,7 @@ class UserAdminTest(TestCase):
     """
     Tests user CRUD functionality.
     """
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2928,6 +2955,7 @@ class GroupAdminTest(TestCase):
     """
     Tests group CRUD functionality.
     """
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -2961,6 +2989,7 @@ except ImportError:
 
 #@unittest.skipUnless(docutils, "no docutils installed.")
 class AdminDocsTest(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -3003,6 +3032,7 @@ class AdminDocsTest(TestCase):
 AdminDocsTest = unittest.skipUnless(docutils, "no docutils installed.")(AdminDocsTest)
 
 class ValidXHTMLTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
     urlbit = 'admin'
 
@@ -3033,6 +3063,7 @@ class ValidXHTMLTests(TestCase):
 
 
 class DateHierarchyTests(TestCase):
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
@@ -3162,6 +3193,7 @@ class AdminCustomSaveRelatedTests(TestCase):
     Ensure that one can easily customize the way related objects are saved.
     Refs #16115.
     """
+    urls = "regressiontests.admin_views.urls"
     fixtures = ['admin-views-users.xml']
 
     def setUp(self):
diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py
index 7320a3c..9f41c95 100644
--- a/tests/regressiontests/admin_views/urls.py
+++ b/tests/regressiontests/admin_views/urls.py
@@ -2,10 +2,11 @@ from django.conf.urls import patterns, include
 from django.contrib import admin
 import views
 import customadmin
+import admin
 
 urlpatterns = patterns('',
-    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
-    (r'^admin/secure-view/$', views.secure_view),
-    (r'^admin/', include(admin.site.urls)),
-    (r'^admin2/', include(customadmin.site.urls)),
+    (r'^test_admin/admin/doc/', include('django.contrib.admindocs.urls')),
+    (r'^test_admin/admin/secure-view/$', views.secure_view),
+    (r'^test_admin/admin/', include(admin.site.urls)),
+    (r'^test_admin/admin2/', include(customadmin.site.urls)),
 )
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index d307030..07bcab7 100644
--- a/tests/regressiontests/cache/tests.py
+++ b/tests/regressiontests/cache/tests.py
@@ -1591,6 +1591,8 @@ TestWithTemplateResponse = override_settings(
 
 class TestEtagWithAdmin(TestCase):
     # See https://code.djangoproject.com/ticket/16003
+    urls = "regressiontests.admin_views.urls"
+
     def test_admin(self):
         with self.settings(USE_ETAGS=False):
             response = self.client.get('/test_admin/admin/')
diff --git a/tests/regressiontests/generic_inline_admin/admin.py b/tests/regressiontests/generic_inline_admin/admin.py
new file mode 100644
index 0000000..87224ed
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/admin.py
@@ -0,0 +1,44 @@
+from django.contrib import admin
+from django.contrib.contenttypes import generic
+
+from models import (Media, PhoneNumber, Episode, EpisodeExtra, Contact,
+    Category, EpisodePermanent, EpisodeMaxNum)
+
+site = admin.AdminSite(name="admin")
+
+class MediaInline(generic.GenericTabularInline):
+    model = Media
+
+
+class EpisodeAdmin(admin.ModelAdmin):
+    inlines = [
+        MediaInline,
+    ]
+
+
+class MediaExtraInline(generic.GenericTabularInline):
+    model = Media
+    extra = 0
+
+
+class MediaMaxNumInline(generic.GenericTabularInline):
+    model = Media
+    extra = 5
+    max_num = 2
+
+
+class PhoneNumberInline(generic.GenericTabularInline):
+    model = PhoneNumber
+
+
+class MediaPermanentInline(generic.GenericTabularInline):
+    model = Media
+    can_delete = False
+
+
+site.register(Episode, EpisodeAdmin)
+site.register(EpisodeExtra, inlines=[MediaExtraInline])
+site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
+site.register(Contact, inlines=[PhoneNumberInline])
+site.register(Category)
+site.register(EpisodePermanent, inlines=[MediaPermanentInline])
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py
index 32ecd3b..e78f110 100644
--- a/tests/regressiontests/generic_inline_admin/models.py
+++ b/tests/regressiontests/generic_inline_admin/models.py
@@ -1,13 +1,14 @@
 from django.db import models
-from django.contrib import admin
 from django.contrib.contenttypes import generic
 from django.contrib.contenttypes.models import ContentType
 
+
 class Episode(models.Model):
     name = models.CharField(max_length=100)
     length = models.CharField(max_length=100, blank=True)
     author = models.CharField(max_length=100, blank=True)
 
+
 class Media(models.Model):
     """
     Media that can associated to any object.
@@ -22,15 +23,6 @@ class Media(models.Model):
     def __unicode__(self):
         return self.url
 
-class MediaInline(generic.GenericTabularInline):
-    model = Media
-
-class EpisodeAdmin(admin.ModelAdmin):
-    inlines = [
-        MediaInline,
-    ]
-admin.site.register(Episode, EpisodeAdmin)
-
 #
 # These models let us test the different GenericInline settings at
 # different urls in the admin site.
@@ -43,34 +35,21 @@ admin.site.register(Episode, EpisodeAdmin)
 class EpisodeExtra(Episode):
     pass
 
-class MediaExtraInline(generic.GenericTabularInline):
-    model = Media
-    extra = 0
-
-admin.site.register(EpisodeExtra, inlines=[MediaExtraInline])
 
 #
 # Generic inline with extra and max_num
 #
-
 class EpisodeMaxNum(Episode):
     pass
 
-class MediaMaxNumInline(generic.GenericTabularInline):
-    model = Media
-    extra = 5
-    max_num = 2
-
-admin.site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])
-
 
 #
 # Generic inline with unique_together
 #
-
 class Category(models.Model):
     name = models.CharField(max_length=50)
 
+
 class PhoneNumber(models.Model):
     content_type = models.ForeignKey(ContentType)
     object_id = models.PositiveIntegerField()
@@ -81,25 +60,15 @@ class PhoneNumber(models.Model):
     class Meta:
         unique_together = (('content_type', 'object_id', 'phone_number',),)
 
+
 class Contact(models.Model):
     name = models.CharField(max_length=50)
     phone_numbers = generic.GenericRelation(PhoneNumber)
 
-class PhoneNumberInline(generic.GenericTabularInline):
-    model = PhoneNumber
-
-admin.site.register(Contact, inlines=[PhoneNumberInline])
-admin.site.register(Category)
-
 #
 # Generic inline with can_delete=False
 #
-
 class EpisodePermanent(Episode):
     pass
 
-class MediaPermanentInline(generic.GenericTabularInline):
-    model = Media
-    can_delete = False
 
-admin.site.register(EpisodePermanent, inlines=[MediaPermanentInline])
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index da59922..858d6a5 100644
--- a/tests/regressiontests/generic_inline_admin/tests.py
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -10,10 +10,12 @@ from django.test import TestCase
 
 # local test models
 from models import (Episode, EpisodeExtra, EpisodeMaxNum, Media,
-    MediaInline, EpisodePermanent, MediaPermanentInline, Category)
+    EpisodePermanent, Category)
+from admin import MediaInline, MediaPermanentInline
 
 
 class GenericAdminViewTest(TestCase):
+    urls = "regressiontests.generic_inline_admin.urls"
     fixtures = ['users.xml']
 
     def setUp(self):
@@ -125,6 +127,7 @@ class GenericAdminViewTest(TestCase):
         self.assertTrue(formset.get_queryset().ordered)
 
 class GenericInlineAdminParametersTest(TestCase):
+    urls = "regressiontests.generic_inline_admin.urls"
     fixtures = ['users.xml']
 
     def setUp(self):
@@ -177,6 +180,7 @@ class GenericInlineAdminParametersTest(TestCase):
 
 
 class GenericInlineAdminWithUniqueTogetherTest(TestCase):
+    urls = "regressiontests.generic_inline_admin.urls"
     fixtures = ['users.xml']
 
     def setUp(self):
@@ -203,6 +207,8 @@ class GenericInlineAdminWithUniqueTogetherTest(TestCase):
         self.assertEqual(response.status_code, 302) # redirect somewhere
 
 class NoInlineDeletionTest(TestCase):
+    urls = "regressiontests.generic_inline_admin.urls"
+
     def test_no_deletion(self):
         fake_site = object()
         inline = MediaPermanentInline(EpisodePermanent, fake_site)
@@ -211,6 +217,7 @@ class NoInlineDeletionTest(TestCase):
         self.assertFalse(formset.can_delete)
 
 class GenericInlineModelAdminTest(TestCase):
+    urls = "regressiontests.generic_inline_admin.urls"
 
     def setUp(self):
         self.site = AdminSite()
diff --git a/tests/regressiontests/generic_inline_admin/urls.py b/tests/regressiontests/generic_inline_admin/urls.py
index f415872..03431d3 100644
--- a/tests/regressiontests/generic_inline_admin/urls.py
+++ b/tests/regressiontests/generic_inline_admin/urls.py
@@ -1,6 +1,7 @@
 from django.conf.urls import patterns, include
-from django.contrib import admin
+
+import admin
 
 urlpatterns = patterns('',
-    (r'^admin/', include(admin.site.urls)),
+    (r'^generic_inline_admin/admin/', include(admin.site.urls)),
 )
diff --git a/tests/urls.py b/tests/urls.py
index 654111d..e7c23e5 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,6 +1,5 @@
 from django.conf.urls import patterns, include
 
-
 urlpatterns = patterns('',
     # test_client modeltest urls
     (r'^test_client/', include('modeltests.test_client.urls')),
@@ -22,11 +21,10 @@ urlpatterns = patterns('',
     # test urlconf for middleware tests
     (r'^middleware/', include('regressiontests.middleware.urls')),
 
-    # admin view tests
-    (r'^test_admin/', include('regressiontests.admin_views.urls')),
-    (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),
-
     # admin widget tests
     (r'widget_admin/', include('regressiontests.admin_widgets.urls')),
 
+    # admin custom URL tests
+    (r'^custom_urls/', include('regressiontests.admin_custom_urls.urls')),
+
 )
