Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔙 from #748 - 🐛 Check for 'field', 'suggest' and 'ordering' API parameters in HTTP POST. #749

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions g3w-admin/core/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,18 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view):

qgis_layer = metadata_layer.qgis_layer

if request.query_params.get('search'):
# Try to get param from GET
search_value = request.query_params.get('search')

if not search_value:
# Try to get from POST
search_value = request.data.get('search')

if search_value:

search_parts = []

for search_term in request.query_params.get('search').split(','):
for search_term in search_value.split(','):

search_term = self._quote_value('%' + search_term + '%')
exp_template = '{field_name} ILIKE ' + search_term
Expand Down Expand Up @@ -115,11 +122,18 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view):

qgis_layer = metadata_layer.qgis_layer

if request.query_params.get('ordering') is not None:
# Try to get param from GET
ordering_value = request.query_params.get('ordering')

if not ordering_value:
# Try to get from POST
ordering_value = request.data.get('ordering')

if ordering_value is not None:

ordering_rules = []

for ordering in request.query_params.get('ordering').split(','):
for ordering in ordering_value.split(','):
ascending = True
if ordering.startswith('-'):
ordering = ordering[1:]
Expand Down Expand Up @@ -216,8 +230,13 @@ def apply_filter(self, request, metadata_layer, qgis_feature_request, view):

qgis_layer = metadata_layer.qgis_layer

# Try to get param from GET
suggest_value = request.query_params.get('suggest')

if not suggest_value:
# Try to get from POST
suggest_value = request.data.get('suggest')

if suggest_value:

# get field and value
Expand Down
Binary file modified g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg
Binary file not shown.
95 changes: 92 additions & 3 deletions g3w-admin/qdjango/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,11 +729,11 @@ def tearDownClass(cls):
cls.project328_value_relation.instance.delete()
super().tearDownClass()

def _testApiCall(self, view_name, args, kwargs={}, status_auth=200, login=True, logout=True):
def _testApiCall(self, view_name, args, kwargs={}, status_auth=200, login=True, logout=True, method='get'):
"""Utility to make test calls for admin01 user"""

path = reverse(view_name, args=args)
if kwargs:
if kwargs and method == 'get':
path += '?'
parts = []
for k, v in kwargs.items():
Expand All @@ -749,7 +749,8 @@ def _testApiCall(self, view_name, args, kwargs={}, status_auth=200, login=True,
if login:
self.assertTrue(self.client.login(
username='admin01', password='admin01'))
response = self.client.get(path)

response = getattr(self.client, method)(path, data=kwargs)
self.assertEqual(response.status_code, status_auth)
if logout:
self.client.logout()
Expand Down Expand Up @@ -1550,6 +1551,7 @@ def test_server_filters_combination_api(self):
qgs_request.setFilterExpression('"ISO2_CODE" = \'IT\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1559,6 +1561,17 @@ def test_server_filters_combination_api(self):

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|eq|IT'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)

qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression(
'"ISO2_CODE" = \'IT\' OR "ISO2_CODE" = \'FR\'')
Expand All @@ -1578,6 +1591,7 @@ def test_server_filters_combination_api(self):
'"ISO2_CODE" = \'IT\' AND "POPULATION" > 10000 OR "ISO2_CODE" = \'FR\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1587,6 +1601,17 @@ def test_server_filters_combination_api(self):

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|eq|IT|AND,POPULATION|gt|10000|OR,ISO2_CODE|eq|FR',
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)

qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression('"NAME" LIKE \'%Flo%\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])
Expand All @@ -1604,6 +1629,7 @@ def test_server_filters_combination_api(self):
qgs_request.setFilterExpression('"NAME" ILIKE \'%flo%\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1613,11 +1639,23 @@ def test_server_filters_combination_api(self):

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': 'NAME|ilike|flo'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)

qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression(
'"ISO2_CODE" = \'IT\' AND "NAME" = \'Florence\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1627,12 +1665,24 @@ def test_server_filters_combination_api(self):

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|eq|IT,NAME|eq|Florence'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)

# check SuggestFilterBackend
# --------------------------
qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression('"NAME" ILIKE \'%flo%\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1642,13 +1692,25 @@ def test_server_filters_combination_api(self):

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],
{
'suggest': 'NAME|flo'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)

# check SuggestFilterBackend + FieldFilterBackend
# -----------------------------------------------
qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression(
'"NAME" ILIKE \'%flo%\' AND "ISO2_CODE" = \'IT\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1660,11 +1722,25 @@ def test_server_filters_combination_api(self):
self.assertEqual(resp['vector']['count'], total_count)
self.assertEqual(resp['vector']['count'], 2)

# Test http 'post' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
{
'suggest': 'NAME|flo',
'field': 'ISO2_CODE|eq|IT'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)
self.assertEqual(resp['vector']['count'], 2)

qgs_request = QgsFeatureRequest()
qgs_request.setFilterExpression(
'"NAME" ILIKE \'%flo%\' AND "ISO2_CODE" = \'IT\' AND "NAME" = \'Florence\'')
total_count = len([f for f in qgis_layer.getFeatures(qgs_request)])

# Test http 'get' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
Expand All @@ -1676,6 +1752,19 @@ def test_server_filters_combination_api(self):
self.assertEqual(resp['vector']['count'], total_count)
self.assertEqual(resp['vector']['count'], 1)

# Test http 'post' method:
resp = json.loads(self._testApiCall('core-vector-api',
['data', 'qdjango', self.project310.instance.pk,
cities.qgs_layer_id],
{
'suggest': 'NAME|flo',
'field': 'ISO2_CODE|eq|IT,NAME|eq|Florence'
},
method='post').content)

self.assertEqual(resp['vector']['count'], total_count)
self.assertEqual(resp['vector']['count'], 1)

def test_unique_request_api_param(self):
""" Test 'unique' url request param for 'data' vector API """

Expand Down