Open knackjax opened 6 years ago
I added this in as a subclass implementation, please let me know if you want a PR.
rest_framework_elasticsearch_ext.es_filters_ext
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from elasticsearch_dsl import Q
from rest_framework_elasticsearch.es_filters import BaseEsFilterBackend
GEO_BOUNDING_BOX_PARAM = 'location__geo_bounding_box'
class ElasticGeoBoundingBoxFilter(BaseEsFilterBackend):
geo_bounding_box_param = GEO_BOUNDING_BOX_PARAM
def get_geo_bounding_box_params(self, request, view):
"""
Geo bounding box are set by a ?location__geo_bounding_box=... query parameter,
and may be comma and/or whitespace delimited.
"""
s_fields = view.get_es_geo_bounding_box_fields()
if not s_fields:
return {}
values = request.query_params.get(self.geo_bounding_box_param, '').split('|')
if len(values) < 2:
return {}
top_left_points = {}
bottom_right_points = {}
options = {}
# Top left
lat_lon = values[0].split(
','
)
if len(lat_lon) >= 2:
top_left_points.update({
'lat': float(lat_lon[0]),
'lon': float(lat_lon[1]),
})
# Bottom right
lat_lon = values[1].split(
','
)
if len(lat_lon) >= 2:
bottom_right_points.update({
'lat': float(lat_lon[0]),
'lon': float(lat_lon[1]),
})
# Options
for value in values[2:]:
if ':' in value:
opt_name_val = value.split(
':'
)
if len(opt_name_val) >= 2:
if opt_name_val[0] in ('_name', 'validation_method', 'type'):
options.update(
{
opt_name_val[0]: opt_name_val[1]
}
)
if not top_left_points or not bottom_right_points:
return {}
params = {}
for s_field in s_fields:
param = {
s_field.name: {
'top_left': top_left_points,
'bottom_right': bottom_right_points,
}
}
params.update(param)
params.update(options)
return params
def filter_search(self, request, search, view):
s_params = self.get_geo_bounding_box_params(request, view)
if not s_params:
return search
print(s_params)
q = Q('geo_bounding_box', **s_params)
search = search.query(q)
return search
rest_framework_elasticsearch_ext.es_filters_ext
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from rest_framework_elasticsearch import es_views
from rest_framework_elasticsearch.es_mixins import ListElasticMixin
from rest_framework_elasticsearch.es_pagination import ElasticLimitOffsetPagination
class ElasticAPIViewExt(es_views.ElasticAPIView):
"""Elasticsearch base API view class."""
def get_es_geo_bounding_box_fields(self):
"""
Return field or fields used for search.
The return value must be an iterable.
"""
return getattr(self, 'es_geo_bounding_box_fields', None)
class ListElasticAPIViewExt(ListElasticMixin, ElasticAPIViewExt):
"""Concrete view for listing a queryset."""
es_pagination_class = ElasticLimitOffsetPagination
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
Hello @knackjax, thanks for your proposal. Can you please create PR with all related tests and documentary updates?
I haven't had time to create tests/docs, but I have a branch if you like to look https://github.com/knackjax/django-rest-elasticsearch/tree/gis_queries
@myarik I think, this issue can be closed yet.
can we get geo-spatial queries support? bounding box would be useful for us displaying data on a map.
I imagine having something similar to this library
https://github.com/barseghyanartur/django-elasticsearch-dsl-drf/blob/master/advanced_usage_examples.rst#geo-spatial-features
will take a look if i have time as well for a PR...