diff --git a/g3w-admin/core/api/filters.py b/g3w-admin/core/api/filters.py index e69aa8e12..91929455c 100644 --- a/g3w-admin/core/api/filters.py +++ b/g3w-admin/core/api/filters.py @@ -24,6 +24,7 @@ from urllib.parse import unquote from core.utils.qgisapi import get_qgis_layer, get_qgis_features from qdjango.models import Layer +import re class BaseFilterBackend(): """Base class for QGIS request filters""" @@ -283,7 +284,8 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view): # field can be multiple separated by ',' # i.e. $field=name|eq|Rome,state|eq|Italy - fields = suggest_value.split(',') + pattern = r',(?=(?:[^()]*\([^()]*\))*[^()]*$)' + fields = re.split(pattern, suggest_value) count = 0 nfields = len(fields) @@ -303,6 +305,8 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view): raise ParseError( 'Invalid field string supplied for parameter field') + # Make lowercase field_operator + field_operator = field_operator.lower() if not self._is_valid_field(qgis_layer, field_name): raise Exception( f"{field_name} doesn't belong from layer {qgis_layer.name()}!") @@ -335,6 +339,8 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view): ), ) ) + + qfr.combineFilterExpression(vr_single_search_expression) features = get_qgis_features(relation_qgs_layer, qfr) @@ -348,7 +354,7 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view): quoted_field_value = self._quote_value( f'{pre_post_operator}{unquote(field_value)}{pre_post_operator}') else: - quoted_field_value = field_value + quoted_field_value = unquote(field_value) single_search_expression = '{field_name} {field_operator} {field_value}'.format( field_name=self._quote_identifier(field_name), diff --git a/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg b/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg index 1ba1d58b4..de09d6c50 100644 Binary files a/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg and b/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg differ diff --git a/g3w-admin/qdjango/tests/test_api.py b/g3w-admin/qdjango/tests/test_api.py index 618aa66d7..11d44306d 100644 --- a/g3w-admin/qdjango/tests/test_api.py +++ b/g3w-admin/qdjango/tests/test_api.py @@ -1576,6 +1576,33 @@ def test_server_filters_combination_api(self): self.assertEqual(resp['vector']['count'], total_count) + qgs_request = QgsFeatureRequest() + qgs_request.setFilterExpression('"ISO2_CODE" IN (\'IT\', \'FR\')') + total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) + + # For IN comparator + # ................. + # Test http 'get' method: + resp = json.loads(self._testApiCall('core-vector-api', + ['data', 'qdjango', self.project310.instance.pk, + cities.qgs_layer_id], + { + 'field': 'ISO2_CODE|in|(\'IT\', \'FR\')' + }).content) + + self.assertEqual(resp['vector']['count'], total_count) + + # Test http 'post' method: + resp = json.loads(self._testApiCall('core-vector-api', + ['data', 'qdjango', self.project310.instance.pk, + cities.qgs_layer_id], + { + 'field': 'ISO2_CODE|in|(\'IT\', \'FR\')' + }, + method='post').content) + + self.assertEqual(resp['vector']['count'], total_count) + qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"ISO2_CODE" = \'IT\' OR "ISO2_CODE" = \'FR\'')