Как выполнить запрос на основе местоположения с помощью простого фильтра Django?

#django #django-models #django-views #django-queryset

#django #django-модели #django-просмотры #django-queryset

Вопрос:

Я сохранил координаты пользователя в User модели. Модель Post имеет latitude longitude и radius поле. Только пользователи в этом районе (Post) смогут увидеть это сообщение. Я не знаю, как использовать filter() здесь, поэтому я использовал следующий подход:

 post=Posts.objects.all()
for a in post:
    distance= geopy.distance.geodesic((lat1,lng1), (a.latitude, a.longitude)).km
    print(distance)
    if distance < a.radius:
        p.append(a)    
    else:
        continue
  

Здесь lat1 и lng1 указаны координаты текущего User . Предложите, есть ли лучший способ, поскольку это кажется очень неэффективным.

Комментарии:

1. Вы можете работать с запросами GeoDjango , если используете базу данных PostGIS или SpatiaLite.

2. @WillemVanOnsem я могу, но это много хлопот только для одного простого запроса, который я хочу сделать. Я уверен, что должен быть простой способ сделать это.

3. ну, внутренне часто такие базы данных работают с пространственным k-d деревом для индексации данных. Это заставляет поиск часто принимать O (log n) вместо линейного подхода.

4. @WillemVanOnsem PostGIS это тогда. Спасибо. Я оставлю его открытым на случай, если у кого-то есть уникальный подход к этому.

Ответ №1:

В зависимости от ваших требований вы можете использовать квадрат вместо круга. Предварительно вычислите границы x-max, x-min, y-max и y-min для вашего квадрата, а затем выполните простой User.filter(lat__gt=lat_min, user.lng__gt=lng_min, user.lat__lt=lat_max ... поиск в базе данных.

В прошлом проекте я использовал это:

 def get_latlng_bounderies(lat, lng, distance):
    """
    Return min/max lat/lng values for a distance around a latlng.
    :lat:, :lng: the center of the area.
    :distance: in km, the "radius" around the center point.
    :returns: Two corner points of a square that countains the circle,
              lat_min, lng_min, lat_max, lng_max.
    """
    gc = great_circle(kilometers=distance)
    p0 = gc.destination((lat, lng), 0)
    p90 = gc.destination((lat, lng), 90)
    p180 = gc.destination((lat, lng), 180)
    p270 = gc.destination((lat, lng), 270)

    ret = p180[0], p270[1], p0[0], p90[1]
    return ret
  

Это не круг, поэтому он не точен вокруг «углов» квадрата, но намного быстрее, потому что это простое сравнение с плавающей точкой в базе данных.

Комментарии:

1. Это очень умный способ обойти эту проблему. Я проанализирую свои требования и, возможно, воспользуюсь этим. Спасибо за такой отличный ответ.