Фильтрация по расстоянию учитывая широту и долготу Django Filter
Пишу проект на Django + DRF. Имеется модель пользователя с заданной широтой и долготой! Во views выводится список пользователей с возможностью фильтрации по расстоянию, например все пользователи в радиусе 10 км от request.user. Саму функцию определения расстояния реализовал, фильтр тоже (через get_queryset), но возникла проблема, не пойму как получать в json само значение distance, расстояние с конкретным пользователем. Подскажите пожалуйста.
class Profiles(models.Model):
""" Модель участников """
user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='Пользователь')
longitude = models.FloatField(verbose_name='Долгота')
latitude = models.FloatField(verbose_name='Широта')
views.py
class ProfilesListView(ListAPIView):
""" Эндпоинт списка участников """
serializer_class = ProfilesListSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = ProfilesFilter
filter_fields = ['distance']
def get_queryset(self):
try:
distance = float(self.request.GET.get('distance'))
mylon = self.request.user.profiles.longitude
mylat = self.request.user.profiles.latitude
lon1 = mylon - distance / abs(cos(radians(mylat)) * 111.0)
lon2 = mylon + distance / abs(cos(radians(mylat)) * 111.0)
lat1 = mylat - (distance / 111.0)
lat2 = mylat + (distance / 111.0)
queryset = Profiles.objects.filter(latitude__range=(lat1, lat2)).filter(longitude__range=(lon1, lon2))
return queryset
except TypeError:
queryset = Profiles.objects.all()
return queryset
serializers.py
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
class ProfilesListSerializer(serializers.ModelSerializer):
user = UsersSerializer()
class Meta:
model = Profiles
exclude = ['id']
Класс фильтрации и метод вычисляющий расстояние
def get_distance_between_users(lon1, lat1, lon2, lat2):
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
dlon = lon2 - lon1
dlat = lat2 - lat1
length = 2 * asin(sqrt(sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2))
km = 6371 * length
return round(km, 3)
class CharFilterInFilter(filters.BaseInFilter, filters.CharFilter):
pass
class ProfilesFilter(filters.FilterSet):
""" Фильтрация участников по полу имени и фамилии """
first_name = CharFilterInFilter(field_name='user__first_name', lookup_expr='in')
last_name = CharFilterInFilter(field_name='user__last_name', lookup_expr='in')
class Meta:
model = Profiles
fields = ['first_name', 'last_name']
Не пойму как выводить расстояние близжайших пользователей используя метод get_distance_between_users...
Ответы (1 шт):
Если нужно расстояние до пользователя, от конкретной точки, то схематично можно сделать так:
Profiles.objects.filter(...<ваши фильтры>...).annotate(distance=Sqrt(Abs(F('longitude') - longitude) + Abs(F('latitude') - latitude))).order_by('distance')
Расстояние в примере находится по теореме Пифагора.
Где latitude, longitude - координаты точки. до которой ищете расстояния
На случай, если нудо будет исключить записи с нулевой дистанцией
Пример может не работать. тк не проверял, писал по памяти, только посмотрел нужны функции БД (можно найти по прикрепленным ссылкам) чтобы не ошибиться