2929from ...constants import (
3030 ALL_GEO_SPATIAL_LOOKUP_FILTERS_AND_QUERIES ,
3131 LOOKUP_FILTER_GEO_DISTANCE ,
32+ LOOKUP_FILTER_GEO_DISTANCE_RANGE ,
33+ LOOKUP_FILTER_GEO_DISTANCE_GT ,
34+ LOOKUP_FILTER_GEO_DISTANCE_GTE ,
35+ LOOKUP_FILTER_GEO_DISTANCE_LT ,
36+ LOOKUP_FILTER_GEO_DISTANCE_LTE ,
37+ LOOKUP_FILTER_GEO_DISTANCE_FROM ,
38+ LOOKUP_FILTER_GEO_DISTANCE_TO ,
39+ LOOKUP_FILTER_GEO_DISTANCE_INCLUDE_UPPER ,
40+ LOOKUP_FILTER_GEO_DISTANCE_INCLUDE_LOWER ,
3241)
3342from ..mixins import FilterBackendMixin
3443
@@ -102,10 +111,16 @@ def prepare_filter_fields(cls, view):
102111
103112 @classmethod
104113 def get_geo_distance_params (cls , value , field ):
105- """Get params for `geo_distance` query
114+ """Get params for `geo_distance` query.
115+
116+ Example:
117+
118+ /api/articles/?location__geo_distance=2km|43.53|-12.23
106119
107120 :param value:
121+ :param field:
108122 :type value: str
123+ :type field:
109124 :return: Params to be used in `geo_distance` query.
110125 :rtype: dict
111126 """
@@ -130,6 +145,96 @@ def get_geo_distance_params(cls, value, field):
130145
131146 return params
132147
148+ @classmethod
149+ def get_range_params (cls , value , field ):
150+ """Get params for `range` query.
151+
152+ Example:
153+
154+ /api/articles/?location__geo_distance_range=2km|10km|43.53|-12.23
155+
156+ Elasticsearch query:
157+
158+ {
159+ "query": {
160+ "bool" : {
161+ "must" : {
162+ "match_all" : {}
163+ },
164+ "filter" : {
165+ "geo_distance_range" : {
166+ "from" : "200km",
167+ "to" : "400km",
168+ "pin.location" : {
169+ "lat" : 40,
170+ "lon" : -70
171+ }
172+ }
173+ }
174+ }
175+ }
176+ }
177+
178+ :param value:
179+ :param field:
180+ :type: str
181+ :type: str
182+ :return: Params to be used in `range` query.
183+ :rtype: dict
184+ """
185+ __values = cls .split_lookup_value (value , maxsplit = 4 )
186+ __len_values = len (__values )
187+
188+ if __len_values < 4 :
189+ return {}
190+
191+ params = {
192+ 'from' : __values [0 ],
193+ 'to' : __values [1 ],
194+ field : {
195+ 'lat' : __values [2 ],
196+ 'lon' : __values [3 ]
197+ }
198+ }
199+
200+ return params
201+
202+ @classmethod
203+ def get_gte_lte_params (cls , value , lookup , field ):
204+ """Get params for `gte`, `gt`, `lte` and `lt` query.
205+
206+ Examples:
207+
208+ /api/articles/?location__geo_distance_gt=2km|43.53|-12.23
209+ /api/articles/?location__geo_distance_gte=2km|43.53|-12.23
210+ /api/articles/?location__geo_distance_lt=2km|43.53|-12.23
211+ /api/articles/?location__geo_distance_lte=2km|43.53|-12.23
212+
213+ :param value:
214+ :param lookup:
215+ :param field:
216+ :type value: str
217+ :type lookup: str
218+ :type field: str
219+ :return: Params to be used in `range` query.
220+ :rtype: dict
221+ """
222+ __values = cls .split_lookup_value (value , maxsplit = 3 )
223+ __len_values = len (__values )
224+
225+ if __len_values < 3 :
226+ return {}
227+
228+ params = {
229+ lookup : __values [0 ],
230+ field : {
231+ 'lat' : __values [2 ],
232+ 'lon' : __values [3 ]
233+ }
234+ }
235+
236+ return params
237+
133238 @classmethod
134239 def apply_query_geo_distance (cls , queryset , options , value ):
135240 """Apply `wildcard` filter.
@@ -150,6 +255,96 @@ def apply_query_geo_distance(cls, queryset, options, value):
150255 )
151256 )
152257
258+ @classmethod
259+ def apply_query_geo_distance_range (cls , queryset , options , value ):
260+ """Apply `range` filter.
261+
262+ :param queryset: Original queryset.
263+ :param options: Filter options.
264+ :param value: value to filter on.
265+ :type queryset: elasticsearch_dsl.search.Search
266+ :type options: dict
267+ :type value: str
268+ :return: Modified queryset.
269+ :rtype: elasticsearch_dsl.search.Search
270+ """
271+ return queryset .filter (
272+ 'geo_distance_range' ,
273+ ** cls .get_range_params (value , options ['field' ])
274+ )
275+
276+ @classmethod
277+ def apply_query_geo_distance_gt (cls , queryset , options , value ):
278+ """Apply `gt` filter.
279+
280+ :param queryset: Original queryset.
281+ :param options: Filter options.
282+ :param value: value to filter on.
283+ :type queryset: elasticsearch_dsl.search.Search
284+ :type options: dict
285+ :type value: str
286+ :return: Modified queryset.
287+ :rtype: elasticsearch_dsl.search.Search
288+ """
289+ return queryset .filter (
290+ 'geo_distance_range' ,
291+ ** cls .get_gte_lte_params (value , 'gt' , options ['field' ])
292+ )
293+
294+ @classmethod
295+ def apply_query_geo_distance_gte (cls , queryset , options , value ):
296+ """Apply `gte` filter.
297+
298+ :param queryset: Original queryset.
299+ :param options: Filter options.
300+ :param value: value to filter on.
301+ :type queryset: elasticsearch_dsl.search.Search
302+ :type options: dict
303+ :type value: str
304+ :return: Modified queryset.
305+ :rtype: elasticsearch_dsl.search.Search
306+ """
307+ return queryset .filter (
308+ 'geo_distance_range' ,
309+ ** cls .get_gte_lte_params (value , 'gte' , options ['field' ])
310+ )
311+
312+ @classmethod
313+ def apply_query_geo_distance_lt (cls , queryset , options , value ):
314+ """Apply `lt` filter.
315+
316+ :param queryset: Original queryset.
317+ :param options: Filter options.
318+ :param value: value to filter on.
319+ :type queryset: elasticsearch_dsl.search.Search
320+ :type options: dict
321+ :type value: str
322+ :return: Modified queryset.
323+ :rtype: elasticsearch_dsl.search.Search
324+ """
325+ return queryset .filter (
326+ 'geo_distance_range' ,
327+ ** cls .get_gte_lte_params (value , 'lt' , options ['field' ])
328+ )
329+
330+ @classmethod
331+ def apply_query_geo_distance_lte (cls , queryset , options , value ):
332+ """Apply `lte` filter.
333+
334+ :param queryset: Original queryset.
335+ :param options: Filter options.
336+ :param value: value to filter on.
337+ :type queryset: elasticsearch_dsl.search.Search
338+ :type options: dict
339+ :type value: str
340+ :return: Modified queryset.
341+ :rtype: elasticsearch_dsl.search.Search
342+ """
343+ return queryset .filter (
344+ 'geo_distance_range' ,
345+ ** cls .get_gte_lte_params (value , 'lte' , options ['field' ])
346+ )
347+
153348 def get_filter_query_params (self , request , view ):
154349 """Get query params to be filtered on.
155350
@@ -216,15 +411,65 @@ def filter_queryset(self, request, queryset, view):
216411 # For all other cases, when we don't have multiple values,
217412 # we follow the normal flow.
218413 for value in options ['values' ]:
414+
219415 # `geo_distance` filter lookup
220416 if options ['lookup' ] == LOOKUP_FILTER_GEO_DISTANCE :
221- queryset = self .apply_query_geo_distance (queryset ,
222- options ,
223- value )
224-
225- # # `geo_distance` filter lookup
226- # else:
227- # queryset = self.apply_query_geo_distance(queryset,
228- # options,
229- # value)
417+ queryset = self .apply_query_geo_distance (
418+ queryset ,
419+ options ,
420+ value
421+ )
422+
423+ # `geo_distance_range` `range` filter lookup
424+ elif options ['lookup' ] == LOOKUP_FILTER_GEO_DISTANCE_RANGE :
425+ queryset = self .apply_query_geo_distance_range (
426+ queryset ,
427+ options ,
428+ value
429+ )
430+
431+ # `geo_distance_range` `gt` filter lookup
432+ elif options ['lookup' ] in (
433+ LOOKUP_FILTER_GEO_DISTANCE_GT ,
434+ LOOKUP_FILTER_GEO_DISTANCE_FROM
435+ ):
436+ queryset = self .apply_query_geo_distance_gt (
437+ queryset ,
438+ options ,
439+ value
440+ )
441+
442+ # `geo_distance_range` `gte` filter lookup
443+ elif options ['lookup' ] in (
444+ LOOKUP_FILTER_GEO_DISTANCE_GTE ,
445+ LOOKUP_FILTER_GEO_DISTANCE_INCLUDE_LOWER
446+ ):
447+ queryset = self .apply_query_geo_distance_gte (
448+ queryset ,
449+ options ,
450+ value
451+ )
452+
453+ # `geo_distance_range` `lt` filter lookup
454+ elif options ['lookup' ] in (
455+ LOOKUP_FILTER_GEO_DISTANCE_LT ,
456+ LOOKUP_FILTER_GEO_DISTANCE_TO
457+ ):
458+ queryset = self .apply_query_geo_distance_lt (
459+ queryset ,
460+ options ,
461+ value
462+ )
463+
464+ # `geo_distance_range` `lte` lookup
465+ elif options ['lookup' ] == (
466+ LOOKUP_FILTER_GEO_DISTANCE_LTE ,
467+ LOOKUP_FILTER_GEO_DISTANCE_INCLUDE_UPPER
468+ ):
469+ queryset = self .apply_query_geo_distance_lte (
470+ queryset ,
471+ options ,
472+ value
473+ )
474+
230475 return queryset
0 commit comments