From 2fc6c9472cd25910f978fe1d18de5c350370f901 Mon Sep 17 00:00:00 2001
From: Loic Bistuer <loic.bistuer@sixmedia.com>
Date: Fri, 19 Jul 2013 02:17:40 +0700
Subject: [PATCH] Fixed #20767 -- Fixed ModelAdmin.preserve_filters for
 namespaced URLs.

Thanks Collin Anderson for the report.
---
 django/contrib/admin/options.py               |  6 ++----
 .../contrib/admin/templatetags/admin_urls.py  |  2 +-
 tests/admin_views/admin.py                    |  5 +++++
 tests/admin_views/tests.py                    | 21 +++++++++++++------
 tests/admin_views/urls.py                     |  1 +
 5 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 9c92f7ae9c..afc7cfc5bd 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -771,12 +771,10 @@ class ModelAdmin(BaseModelAdmin):
         Returns the preserved filters querystring.
         """
 
-        # FIXME: We can remove that getattr as soon as #20619 is fixed.
-        match = getattr(request, 'resolver_match', None)
-
+        match = request.resolver_match
         if self.preserve_filters and match:
             opts = self.model._meta
-            current_url = '%s:%s' % (match.namespace, match.url_name)
+            current_url = '%s:%s' % (match.app_name, match.url_name)
             changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name)
             if current_url == changelist_url:
                 preserved_filters = request.GET.urlencode()
diff --git a/django/contrib/admin/templatetags/admin_urls.py b/django/contrib/admin/templatetags/admin_urls.py
index 19da87d61f..5d9c5b5427 100644
--- a/django/contrib/admin/templatetags/admin_urls.py
+++ b/django/contrib/admin/templatetags/admin_urls.py
@@ -38,7 +38,7 @@ def add_preserved_filters(context, url, popup=False):
         except Resolver404:
             pass
         else:
-            current_url = '%s:%s' % (match.namespace, match.url_name)
+            current_url = '%s:%s' % (match.app_name, match.url_name)
             changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name)
             if changelist_url == current_url and '_changelist_filters' in preserved_filters:
                 preserved_filters = dict(parse_qsl(preserved_filters['_changelist_filters']))
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index a6ad7cc0bc..039abb819b 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -777,3 +777,8 @@ from django.contrib.auth.models import User, Group
 from django.contrib.auth.admin import UserAdmin, GroupAdmin
 site.register(User, UserAdmin)
 site.register(Group, GroupAdmin)
+
+# Used to test URL namespaces
+site2 = admin.AdminSite(name="namespaced_admin")
+site2.register(User, UserAdmin)
+site2.register(Group, GroupAdmin)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 101fcd90f6..a83c756a25 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -26,7 +26,6 @@ from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
 from django.contrib.auth import REDIRECT_FIELD_NAME
 from django.contrib.auth.models import Group, User, Permission
 from django.contrib.contenttypes.models import ContentType
-from django.core.urlresolvers import reverse
 from django.db import connection
 from django.forms.util import ErrorList
 from django.template.response import TemplateResponse
@@ -53,6 +52,7 @@ from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount,
     AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable,
     Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject,
     Simple, UndeletableObject, Choice, ShortMessage, Telegram)
+from .admin import site, site2
 
 
 ERROR_MESSAGE = "Please enter the correct username and password \
@@ -4186,6 +4186,7 @@ class AdminUserMessageTest(TestCase):
 class AdminKeepChangeListFiltersTests(TestCase):
     urls = "admin_views.urls"
     fixtures = ['admin-views-users.xml']
+    admin_site = site
 
     def setUp(self):
         self.client.login(username='super', password='secret')
@@ -4209,13 +4210,15 @@ class AdminKeepChangeListFiltersTests(TestCase):
 
     def get_changelist_url(self):
         return '%s?%s' % (
-            reverse('admin:auth_user_changelist'),
+            reverse('admin:auth_user_changelist',
+                    current_app=self.admin_site.name),
             self.get_changelist_filters_querystring(),
         )
 
     def get_add_url(self):
         return '%s?%s' % (
-            reverse('admin:auth_user_add'),
+            reverse('admin:auth_user_add',
+                    current_app=self.admin_site.name),
             self.get_preserved_filters_querystring(),
         )
 
@@ -4223,7 +4226,8 @@ class AdminKeepChangeListFiltersTests(TestCase):
         if user_id is None:
             user_id = self.get_sample_user_id()
         return "%s?%s" % (
-            reverse('admin:auth_user_change', args=(user_id,)),
+            reverse('admin:auth_user_change', args=(user_id,),
+                    current_app=self.admin_site.name),
             self.get_preserved_filters_querystring(),
         )
 
@@ -4231,7 +4235,8 @@ class AdminKeepChangeListFiltersTests(TestCase):
         if user_id is None:
             user_id = self.get_sample_user_id()
         return "%s?%s" % (
-            reverse('admin:auth_user_history', args=(user_id,)),
+            reverse('admin:auth_user_history', args=(user_id,),
+                    current_app=self.admin_site.name),
             self.get_preserved_filters_querystring(),
         )
 
@@ -4239,7 +4244,8 @@ class AdminKeepChangeListFiltersTests(TestCase):
         if user_id is None:
             user_id = self.get_sample_user_id()
         return "%s?%s" % (
-            reverse('admin:auth_user_delete', args=(user_id,)),
+            reverse('admin:auth_user_delete', args=(user_id,),
+                    current_app=self.admin_site.name),
             self.get_preserved_filters_querystring(),
         )
 
@@ -4333,3 +4339,6 @@ class AdminKeepChangeListFiltersTests(TestCase):
         # Test redirect on "Delete".
         response = self.client.post(self.get_delete_url(), {'post': 'yes'})
         self.assertRedirects(response, self.get_changelist_url())
+
+class NamespacedAdminKeepChangeListFiltersTests(AdminKeepChangeListFiltersTests):
+    admin_site = site2
diff --git a/tests/admin_views/urls.py b/tests/admin_views/urls.py
index 441834cd2a..763c83a450 100644
--- a/tests/admin_views/urls.py
+++ b/tests/admin_views/urls.py
@@ -12,4 +12,5 @@ urlpatterns = patterns('',
     (r'^test_admin/admin2/', include(customadmin.site.urls)),
     (r'^test_admin/admin3/', include(admin.site.urls), dict(form_url='pony')),
     (r'^test_admin/admin4/', include(customadmin.simple_site.urls)),
+    (r'^test_admin/admin5/', include(admin.site2.urls)),
 )