wcs: add distance filters (#70588)

This commit is contained in:
Frédéric Péters 2022-11-29 10:54:31 +01:00
parent 8f6fd7b2fe
commit 4b16a94262
3 changed files with 82 additions and 2 deletions

View File

@ -33,13 +33,16 @@ def get_default_wcs_service_key():
class LazyCardDefObjectsManager:
def __init__(self, service_key, card_id, custom_view_id=None, filters=None, user=Ellipsis):
def __init__(
self, service_key, card_id, custom_view_id=None, filters=None, geo_center=None, user=Ellipsis
):
self._service_key = service_key
self._card_id = card_id
self._custom_view_id = custom_view_id
self._filters = filters or {}
self._user = user
self._geo_center = geo_center or {}
self._cached_resultset = None
@ -49,6 +52,7 @@ class LazyCardDefObjectsManager:
card_id=self._card_id,
custom_view_id=self._custom_view_id,
filters=self._filters,
geo_center=self._geo_center,
user=self._user,
)
@ -121,7 +125,7 @@ class LazyCardDefObjectsManager:
if isinstance(value, bool):
value = str(value).lower()
op = getattr(self, 'pending_op', 'eq')
if self.pending_attr in ['internal_id', 'number', 'user', 'status']:
if self.pending_attr in ['internal_id', 'number', 'user', 'status', 'distance']:
return getattr(self, 'filter_by_%s' % self.pending_attr)(value, op)
qs._filters['filter-%s' % self.pending_attr] = value
qs._filters['filter-%s-operator' % self.pending_attr] = op
@ -176,6 +180,23 @@ class LazyCardDefObjectsManager:
qs._filters['filter-operator'] = op
return qs
def filter_by_distance(self, distance, op=None):
# distance do not currently support an operator
qs = self._clone()
if distance:
qs._filters['filter-distance'] = distance
return qs
def set_geo_center_lat(self, lat):
qs = self._clone()
qs._geo_center['center_lat'] = lat
return qs
def set_geo_center_lon(self, lon):
qs = self._clone()
qs._geo_center['center_lon'] = lon
return qs
def _get_results_from_wcs(self):
service = get_wcs_services().get(self._service_key)
if not service:
@ -187,6 +208,8 @@ class LazyCardDefObjectsManager:
if self._filters:
query = urlencode(self._filters)
api_url += '?%s' % query
if 'center_lat' in self._geo_center and 'center_lon' in self._geo_center:
api_url += '&' + urlencode(self._geo_center)
without_user = self._user is Ellipsis # not set
try:
response = requests.get(

View File

@ -209,3 +209,27 @@ def order_by(queryset, attribute):
return queryset.order_by(attribute)
except AttributeError:
return None
@register.filter
def filter_by_distance(queryset, distance):
try:
return queryset.filter_by_distance(distance)
except AttributeError:
return None
@register.filter
def set_geo_center_lat(queryset, lat):
try:
return queryset.set_geo_center_lat(lat)
except AttributeError:
return None
@register.filter
def set_geo_center_lon(queryset, lon):
try:
return queryset.set_geo_center_lon(lon)
except AttributeError:
return None

View File

@ -507,6 +507,39 @@ def test_filter_by_status(mock_send, context, nocache):
assert mock_send.call_args_list == []
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_filter_by_distance(mock_send, context, nocache):
t = Template('{{ cards|objects:"foo"|list }}')
t.render(context)
assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url
for tpl in ['filter_by_distance', 'filter_by:"distance"|filter_value']:
mock_send.reset_mock()
t = Template('{{ cards|objects:"foo"|%s:None|list }}' % tpl)
t.render(context)
assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url
mock_send.reset_mock()
t = Template('{{ cards|objects:"foo"|%s:""|list }}' % tpl)
t.render(context)
assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url
mock_send.reset_mock()
t = Template('{{ cards|objects:"foo"|%s:"10000"|list }}' % tpl)
t.render(context)
assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url
mock_send.reset_mock()
t = Template(
'{{ cards|objects:"foo"|set_geo_center_lat:1|set_geo_center_lon:2|%s:"10000"|list }}' % tpl
)
t.render(context)
assert 'center_lat=1&' in mock_send.call_args_list[0][0][0].url
assert 'center_lon=2&' in mock_send.call_args_list[0][0][0].url
assert 'filter-distance=10000&' in mock_send.call_args_list[0][0][0].url
assert 'filter-distance-operator' not in mock_send.call_args_list[0][0][0].url
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_getlist(mock_send, context, nocache):
t = Template('{% for v in cards|objects:"foo"|getlist:"id" %}{{ v }},{% endfor %}')