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)
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -34,11 +34,17 @@ if django_filters:
|
|||
class SeveralFieldsFilter(django_filters.FilterSet):
|
||||
text = django_filters.CharFilter(lookup_type='icontains')
|
||||
decimal = django_filters.NumberFilter(lookup_type='lt')
|
||||
decimal_in = django_filters.MethodFilter(action="filter_decimal_in")
|
||||
date = django_filters.DateFilter(lookup_type='gt')
|
||||
|
||||
class Meta:
|
||||
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):
|
||||
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]
|
||||
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.
|
||||
search_date = datetime.date(2012, 10, 2)
|
||||
request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02'
|
||||
|
|
Loading…
Reference in New Issue
Block a user