mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-06 05:20:12 +03:00
Pass a dict as data to django-filter
In order to filter with multivalue params such as 'in' lookups there are two alternatives: * ?multiparam=1,2,3 * ?multiparam=1&multiparam=2 The second option is a better approach when facing strings. However, by definition QueryDict does only take into account the last param included. Django-filters expect a dict as data. To be congruent with what is passed in the request we need to transform `query_params` to a `dict`. As can be seen in the test written, adhoc programming must be done also in django-filter to allow 'in' lookups but that's another issue. Part of the solution was taken from @leo-the-manic in http://stackoverflow.com/questions/13349573/how-to-change-a-django-querydict-to-python-dict#answer-22100334
This commit is contained in:
parent
235b98e427
commit
7854bd5daf
|
@ -65,7 +65,11 @@ class DjangoFilterBackend(BaseFilterBackend):
|
||||||
filter_class = self.get_filter_class(view, queryset)
|
filter_class = self.get_filter_class(view, queryset)
|
||||||
|
|
||||||
if filter_class:
|
if filter_class:
|
||||||
return filter_class(request.query_params, queryset=queryset).qs
|
# Using solution by @leo-the-manic goo.gl/3LoFIj
|
||||||
|
return filter_class(
|
||||||
|
{k: v[0] if len(v) == 1 else v for k, v in request.query_params.lists()},
|
||||||
|
queryset=queryset
|
||||||
|
).qs
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,17 @@ if django_filters:
|
||||||
class SeveralFieldsFilter(django_filters.FilterSet):
|
class SeveralFieldsFilter(django_filters.FilterSet):
|
||||||
text = django_filters.CharFilter(lookup_type='icontains')
|
text = django_filters.CharFilter(lookup_type='icontains')
|
||||||
decimal = django_filters.NumberFilter(lookup_type='lt')
|
decimal = django_filters.NumberFilter(lookup_type='lt')
|
||||||
|
decimal_in = django_filters.MethodFilter(action="filter_decimal_in")
|
||||||
date = django_filters.DateFilter(lookup_type='gt')
|
date = django_filters.DateFilter(lookup_type='gt')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FilterableItem
|
model = FilterableItem
|
||||||
fields = ['text', 'decimal', 'date']
|
fields = ['text', 'decimal', 'decimal_in', 'date']
|
||||||
|
|
||||||
|
def filter_decimal_in(self, qs, values):
|
||||||
|
if not hasattr(values, '__iter__'):
|
||||||
|
values = (values,)
|
||||||
|
return qs.filter(decimal__in=values)
|
||||||
|
|
||||||
class FilterClassRootView(generics.ListCreateAPIView):
|
class FilterClassRootView(generics.ListCreateAPIView):
|
||||||
queryset = FilterableItem.objects.all()
|
queryset = FilterableItem.objects.all()
|
||||||
|
@ -207,6 +213,16 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
|
||||||
expected_data = [f for f in self.data if Decimal(f['decimal']) < search_decimal]
|
expected_data = [f for f in self.data if Decimal(f['decimal']) < search_decimal]
|
||||||
self.assertEqual(response.data, expected_data)
|
self.assertEqual(response.data, expected_data)
|
||||||
|
|
||||||
|
# Tests that the decimal_in filter set with 'in' in the filter class works
|
||||||
|
search_decimal_in = ['1.25', '2.25']
|
||||||
|
request = factory.get('/', {
|
||||||
|
'decimal_in': search_decimal_in,
|
||||||
|
})
|
||||||
|
response = view(request).render()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
expected_data = [f for f in self.data if f['decimal'] in search_decimal_in]
|
||||||
|
self.assertEqual(response.data, expected_data)
|
||||||
|
|
||||||
# Tests that the date filter set with 'gt' in the filter class works.
|
# Tests that the date filter set with 'gt' in the filter class works.
|
||||||
search_date = datetime.date(2012, 10, 2)
|
search_date = datetime.date(2012, 10, 2)
|
||||||
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02'
|
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user