From b7f99f84bcc4a06114ac31174840efab0aef7602 Mon Sep 17 00:00:00 2001
From: Paulo <commonzenpython@gmail.com>
Date: Sun, 4 Jun 2017 14:10:48 -0400
Subject: [PATCH] Fixed #28262 -- Fixed incorrect DisallowedModelAdminLookup
 when a nested reverse relation is in list_filter.

---
 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 b16a62c785..2a447b7cff 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -357,7 +357,7 @@ class BaseModelAdmin(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 24e6039f80..7c3190574c 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -79,12 +79,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 ea8fc18b5c..2dd7f5efd3 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -69,6 +69,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
@@ -90,6 +91,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 88aadbb399..2f52bd9925 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -609,6 +609,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']: