diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index f7c520a43a..4216f2ea64 100644 --- a/django/contrib/admin/filters.py +++ b/django/contrib/admin/filters.py @@ -166,9 +166,9 @@ class RelatedFieldListFilter(FieldListFilter): self.lookup_kwarg_isnull = '%s__isnull' % field_path self.lookup_val = request.GET.get(self.lookup_kwarg) self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull) - self.lookup_choices = self.field_choices(field, request, model_admin) super(RelatedFieldListFilter, self).__init__( field, request, params, model, model_admin, field_path) + self.lookup_choices = self.field_choices(field, request, model_admin) if hasattr(field, 'verbose_name'): self.lookup_title = field.verbose_name else: @@ -412,5 +412,5 @@ FieldListFilter.register(lambda f: True, AllValuesFieldListFilter) class RelatedOnlyFieldListFilter(RelatedFieldListFilter): def field_choices(self, field, request, model_admin): - limit_choices_to = {'pk__in': set(model_admin.get_queryset(request).values_list(field.name, flat=True))} - return field.get_choices(include_blank=False, limit_choices_to=limit_choices_to) + pk_qs = model_admin.get_queryset(request).distinct().values_list('%s__pk' % self.field_path, flat=True) + return field.get_choices(include_blank=False, limit_choices_to={'pk__in': pk_qs}) diff --git a/tests/admin_filters/models.py b/tests/admin_filters/models.py index 40f25d2f30..db37958882 100644 --- a/tests/admin_filters/models.py +++ b/tests/admin_filters/models.py @@ -26,6 +26,12 @@ class Book(models.Model): related_name='books_contributed', blank=True, ) + employee = models.ForeignKey( + 'Employee', + models.SET_NULL, + verbose_name='Employee', + blank=True, null=True, + ) is_best_seller = models.NullBooleanField(default=0) date_registered = models.DateField(null=True) # This field name is intentionally 2 characters long (#16080). diff --git a/tests/admin_filters/tests.py b/tests/admin_filters/tests.py index f1756a3c64..11f81fc3ed 100644 --- a/tests/admin_filters/tests.py +++ b/tests/admin_filters/tests.py @@ -169,6 +169,7 @@ class BookAdminRelatedOnlyFilter(ModelAdmin): 'year', 'is_best_seller', 'date_registered', 'no', ('author', RelatedOnlyFieldListFilter), ('contributors', RelatedOnlyFieldListFilter), + ('employee__department', RelatedOnlyFieldListFilter), ) ordering = ('-id',) @@ -580,6 +581,26 @@ class ListFiltersTests(TestCase): expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob')] self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected)) + def test_relatedonlyfieldlistfilter_underscorelookup_foreignkey(self): + Department.objects.create(code='TEST', description='Testing') + self.djangonaut_book.employee = self.john + self.djangonaut_book.save() + self.bio_book.employee = self.jack + self.bio_book.save() + + modeladmin = BookAdminRelatedOnlyFilter(Book, site) + request = self.request_factory.get('/') + changelist = self.get_changelist(request, Book, modeladmin) + + # Only actual departments should be present in employee__department's + # list filter. + filterspec = changelist.get_filters(request)[0][6] + expected = [ + (self.dev.code, str(self.dev)), + (self.design.code, str(self.design)), + ] + self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected)) + def test_relatedonlyfieldlistfilter_manytomany(self): modeladmin = BookAdminRelatedOnlyFilter(Book, site)