Vishal Sharma
Vishal Sharma

Reputation: 57

How to set filter range in backend in filter class in django

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

Answers (2)

Andrew
Andrew

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

Andrey Leontyev
Andrey Leontyev

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

Related Questions