diff --git a/rest_framework/filters.py b/rest_framework/filters.py index caff1c17f..aaf313491 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -174,8 +174,8 @@ class SearchFilter(BaseFilterBackend): """ Return True if 'distinct()' should be used to query the given lookups. """ - opts = queryset.model._meta for search_field in search_fields: + opts = queryset.model._meta if search_field[0] in self.lookup_prefixes: search_field = search_field[1:] parts = search_field.split(LOOKUP_SEP) diff --git a/tests/test_filters.py b/tests/test_filters.py index 8bffd215c..175ae5b12 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -454,6 +454,47 @@ class AttributeModel(models.Model): label = models.CharField(max_length=32) +class SearchFilterModelFk(models.Model): + title = models.CharField(max_length=20) + attribute = models.ForeignKey(AttributeModel) + + +class SearchFilterFkSerializer(serializers.ModelSerializer): + class Meta: + model = SearchFilterModelFk + fields = '__all__' + + +class SearchFilterFkTests(TestCase): + + def test_must_call_distinct(self): + filter_ = filters.SearchFilter() + prefixes = [''] + list(filter_.lookup_prefixes) + for prefix in prefixes: + self.assertFalse( + filter_.must_call_distinct( + SearchFilterModelFk._meta, ["%stitle" % prefix] + ) + ) + self.assertFalse( + filter_.must_call_distinct( + SearchFilterModelFk._meta, ["%stitle" % prefix, "%sattribute__label" % prefix] + ) + ) + + def test_must_call_distinct_restores_meta_for_each_field(self): + # In this test case the attribute of the fk model comes first in the + # list of search fields. + filter_ = filters.SearchFilter() + prefixes = [''] + list(filter_.lookup_prefixes) + for prefix in prefixes: + self.assertFalse( + filter_.must_call_distinct( + SearchFilterModelFk._meta, ["%sattribute__label" % prefix, "%stitle" % prefix] + ) + ) + + class SearchFilterModelM2M(models.Model): title = models.CharField(max_length=20) text = models.CharField(max_length=100)