From 834d57b4de80e525195128c88592e0e076708a23 Mon Sep 17 00:00:00 2001 From: Paulo Date: Sun, 4 Jun 2017 14:10:48 -0400 Subject: [PATCH] [1.11.x] Fixed #28262 -- Fixed incorrect DisallowedModelAdminLookup when a nested reverse relation is in list_filter. Backport of b7f99f84bcc4a06114ac31174840efab0aef7602 from master --- django/contrib/admin/options.py | 2 +- docs/releases/1.11.3.txt | 3 +++ tests/admin_views/admin.py | 15 +++++++++------ tests/admin_views/models.py | 2 ++ tests/admin_views/tests.py | 5 +++++ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index aef1e2c24e..0a2c53b3c6 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -360,7 +360,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): # It is allowed to filter on values that would be found from local # model anyways. For example, if you filter on employee__department__id, # then the id value would be found already from employee__department_id. - if not prev_field or (prev_field.concrete and + if not prev_field or (prev_field.is_relation and field not in prev_field.get_path_info()[-1].target_fields): relation_parts.append(part) if not getattr(field, 'get_path_info', None): diff --git a/docs/releases/1.11.3.txt b/docs/releases/1.11.3.txt index ed2bf31cf5..f273a36e9f 100644 --- a/docs/releases/1.11.3.txt +++ b/docs/releases/1.11.3.txt @@ -15,3 +15,6 @@ Bugfixes * Fixed a regression causing ``Model.__init__()`` to crash if a field has an instance only descriptor (:ticket:`28269`). + +* Fixed an incorrect ``DisallowedModelAdminLookup`` exception when using + a nested reverse relation in ``list_filter`` (:ticket:`28262`). diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index e8a1cf3bff..c70bebec87 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -82,12 +82,15 @@ class ChapterInline(admin.TabularInline): class ChapterXtra1Admin(admin.ModelAdmin): - list_filter = ('chap', - 'chap__title', - 'chap__book', - 'chap__book__name', - 'chap__book__promo', - 'chap__book__promo__name',) + list_filter = ( + 'chap', + 'chap__title', + 'chap__book', + 'chap__book__name', + 'chap__book__promo', + 'chap__book__promo__name', + 'guest_author__promo__book', + ) class ArticleAdmin(admin.ModelAdmin): diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py index 86ab055f30..9c7eee7547 100644 --- a/tests/admin_views/models.py +++ b/tests/admin_views/models.py @@ -77,6 +77,7 @@ class Book(models.Model): class Promo(models.Model): name = models.CharField(max_length=100, verbose_name='¿Name?') book = models.ForeignKey(Book, models.CASCADE) + author = models.ForeignKey(User, models.SET_NULL, blank=True, null=True) def __str__(self): return self.name @@ -100,6 +101,7 @@ class Chapter(models.Model): class ChapterXtra1(models.Model): chap = models.OneToOneField(Chapter, models.CASCADE, verbose_name='¿Chap?') xtra = models.CharField(max_length=100, verbose_name='¿Xtra?') + guest_author = models.ForeignKey(User, models.SET_NULL, blank=True, null=True) def __str__(self): return '¿Xtra1: %s' % self.xtra diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 4f281bd01a..febb20914c 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -612,6 +612,11 @@ class AdminViewBasicTest(AdminViewBasicTestCase): 'values': [p.name for p in Promo.objects.all()], 'test': lambda obj, value: obj.chap.book.promo_set.filter(name=value).exists(), }, + # A forward relation (book) after a reverse relation (promo). + 'guest_author__promo__book__id__exact': { + 'values': [p.id for p in Book.objects.all()], + 'test': lambda obj, value: obj.guest_author.promo_set.filter(book=value).exists(), + }, } for filter_path, params in filters.items(): for value in params['values']: