Restore meta information for each search field. (#4298)

The meta information stored in opts needs to be restored for
each search field. Otherwise it references the wrong model
when an attribute of a related model comes before an attribute
of the original model in search fields. This doesn't apply to
m2m relations since must_call_distinct returns True in that
case.
This commit is contained in:
Andi Albrecht 2016-07-26 12:07:03 +02:00 committed by Tom Christie
parent 48465a667a
commit 3ca0b15b17
2 changed files with 42 additions and 1 deletions

View File

@ -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)

View File

@ -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)