Skip to content

Commit

Permalink
Merge pull request #98 from Souleymane-T/feature-add-case-insensitive…
Browse files Browse the repository at this point in the history
…-contains-filter

Add case insensitive contains filter
  • Loading branch information
lcognat committed Sep 3, 2021
2 parents 374742b + 0855371 commit c207836
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### Added

- nothing added
- Case insensitive contains filter

### Changed

Expand Down
45 changes: 45 additions & 0 deletions concrete_datastore/api/v1/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,51 @@ def filter_queryset(self, request, queryset, view):
return queryset.filter(q_object)


class FilterSupportingInsensitiveContainsBackend(
BaseFilterBackend, CustomShemaOperationParameters
):
def get_schema_operation_parameters(self, view):
params = [
{
'name': f'{field_name}__icontains',
'required': False,
'in': 'query',
'schema': {'type': 'string'},
}
for field_name in getattr(view, 'filterset_fields', ())
if get_filter_field_type(view.model_class, field_name)
in ('CharField', 'TextField')
]
return self.return_if_not_details(view=view, value=params)

def filter_queryset(self, request, queryset, view):
query_params = request.query_params
filterset_fields = getattr(view, 'filterset_fields', ())

q_object = None
for param in query_params:
if not param.endswith('__icontains'):
continue
param_field = param.replace('__icontains', '')
if param_field not in filterset_fields:
continue
if not get_filter_field_type(queryset.model, param_field) in (
'CharField',
'TextField',
):
continue

custom_filter = {param: query_params.get(param)}
if q_object is None:
q_object = Q(**custom_filter)
else:
q_object &= Q(**custom_filter)
if q_object is None:
return queryset

return queryset.filter(q_object)


class FilterSupportingEmptyBackend(
BaseFilterBackend, CustomShemaOperationParameters
):
Expand Down
2 changes: 2 additions & 0 deletions concrete_datastore/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
FilterSupportingOrBackend,
FilterSupportingEmptyBackend,
FilterSupportingContainsBackend,
FilterSupportingInsensitiveContainsBackend,
FilterSupportingRangeBackend,
FilterUserByLevel,
FilterSupportingComparaisonBackend,
Expand Down Expand Up @@ -1227,6 +1228,7 @@ class PaginatedViewSet(object):
FilterSupportingOrBackend,
FilterSupportingEmptyBackend,
FilterSupportingContainsBackend,
FilterSupportingInsensitiveContainsBackend,
FilterSupportingRangeBackend,
FilterUserByLevel,
FilterSupportingComparaisonBackend,
Expand Down
37 changes: 37 additions & 0 deletions tests/tests_api_v1_1/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,43 @@ def test_one_result_with_non_char_field(self):
self.assertEqual(names, {'Project1', 'Project2'})


@override_settings(DEBUG=True)
class FilterInsensitiveContainsBackend(APITestCase):
def setUp(self):
self.user = User.objects.create_user('user@netsach.org')
self.user.set_password('plop')
self.user.set_level('superuser')
self.user.save()
confirmation = UserConfirmation.objects.create(user=self.user)
confirmation.confirmed = True
confirmation.save()
url = '/api/v1.1/auth/login/'
resp = self.client.post(
url, {"email": "user@netsach.org", "password": "plop"}
)
self.token = resp.data['token']

self.project1 = Project.objects.create(
name='Project1', description='text of description1'
)
self.project1 = Project.objects.create(
name='Project2', description='text of description2'
)

def test_success_one_result_with_icontain_filter(self):
resp = self.client.get(
'/api/v1.1/project/',
data={'name__icontains': 'pRoJeCt1'},
HTTP_AUTHORIZATION='Token {}'.format(self.token),
)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertIn('results', resp.data)
self.assertIn('total_objects_count', resp.data)
self.assertEqual(resp.data['total_objects_count'], 1)
names = {project['name'] for project in resp.data['results']}
self.assertEqual(names, {'Project1'})


@override_settings(DEBUG=True)
class FilterObjectByUid(APITestCase):
def setUp(self):
Expand Down

0 comments on commit c207836

Please sign in to comment.