Reputation: 57
I'm building a REST API using DRF. I'm using django_filters for filtering result set. In one api I want user to send his coordinates(latitude, longitude) and in backend I create a range as (latitude+2 to latitude-2) and return results, I don't want take range field from user. So I can easily change the range in my backend.
I've created two range filters in filter class that works fine but url looks like this: /posts/?latitude_min=22&latitude_max=28&longitude_min=80&longitude_max=84. And here user is responsible to decide range. I want user send latitude and longitude only, I decide about maximum and minimum range.
class PostFilter(django_filters.FilterSet):
latitude = django_filters.RangeFilter(field_name='latitude')
longitude = django_filters.RangeFilter()
class Meta:
model = Post
fields = ['latitude', 'longitude', 'country', 'state', 'district', ]
Upvotes: 2
Views: 695
Reputation: 8674
You can write a custom filter field that does this, in just a few lines of code. It will give you a bit more flexibility to add validation later as well, or additional logic around the specifics of lat/lng.
class ApproximateNumberFilter(Filter):
field_class = FloatField # use django base float validation
def __init__(self, under_over=2, **kwargs):
super().__init__(**kwargs)
self._under_over = under_over
def filter(self, qs, value):
if value in EMPTY_VALUES:
return qs
return qs.filter(**{
f"{self.field_name}__gte": value - self._under_over,
f"{self.field_name}__lte": value + self._under_over,
})
Upvotes: 2
Reputation: 451
I think you can use 'MethodFilter' something like this:
from django.db.models import Q
class PostFilter(django_filters.FilterSet):
latitude = django_filters.MethodFilter(action="filter_latitude")
longitude = django_filters.MethodFilter(action="filter_longitude")
class Meta:
model = Post
fields = ['latitude', 'longitude', 'country', 'state', 'district']
def filter_latitude(self, qs, value):
try:
return qs.filter(Q(latitude__gte=value-2)&Q(latitude__lte=value+2))
except BaseException:
return qs
def filter_longitude(self, qs, value):
try:
return qs.filter(Q(longitude__gte=value-2)&Q(longitude__lte=value+2))
except BaseException:
return qs
Upvotes: 2