Как получить ближайшие записи местоположения из базы данных?

Я храню координаты в виде пар широты и долготы в моей базе данных. Теперь мне нужно извлечь все записи, которые находятся в заданном радиусе из заданной координаты длины широты. Например, если заданы координаты 48.796777, 2.371140 и расстояние 20 километров, он получит все записи в пределах 20 километров от этой точки.

Если это обеспечивает какое-либо упрощение или приводит к сокращению процессорного времени, достаточно точно рассчитать "прямое" расстояние между точками, то есть нет необходимости учитывать кривизну земли.

Как этого добиться с помощью Django? Более конкретно, как должно быть построено представление (и, возможно, модель) для такого запроса?

5 ответов

Решение

Вы должны использовать GeoDjango. Это позволяет вам выполнять дистанционные запросы в вашей географической базе данных.

from django.contrib.gis.measure import D
from django.contrib.gis.geos import *
from myapp.models import MyResult

pnt = fromstr('POINT(48.796777 2.371140 )', srid=4326)
qs = MyResult.objects.filter(point__distance_lte=(pnt, D(km=20)))

Вы можете использовать геопию

>>> from geopy **import** distance  
>>> _, ne = g.geocode('Newport, RI')  
>>> _, cl = g.geocode('Cleveland, OH')  
>>> distance.distance(ne, cl).miles  
    538.37173614757057

To **optimize** a bit you can **filter** user objects to get a rough estimate of **nearby users first**. This way you don't have to loop over all the users in the db. This rough estimate is optional. To meet all your project requirements you maybe have to write some extra logic:


#The location of your user.
lat, lng = 41.512107999999998, -81.607044999999999 

min_lat = lat - 1 # You have to calculate this offsets based on the user location.
max_lat = lat + 1 # Because the distance of one degree varies over the planet.
min_lng = lng - 1
max_lng = lng + 1    

users = User.objects.filter(lat__gt=min_lat, lat__lt=max__lat, lat__gt=min_lat, lat__lt=max__lat)

# If not 20 fall back to all users.
if users.count() <= 20:
    users = User.objects.all()

Без GeoDjango

Вы могли бы сделать,

      objects = YourModel.objects.raw('SELECT *,  ( 6371 * acos( cos( radians('+my_lat+') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians('+my_long+') ) + sin( radians('+my_lat+') ) * sin( radians( latitude ) ) ) ) AS distance FROM "YourModel" WHERE (6371 * acos( cos( radians('+my_lat+') ) * cos( radians(latitude) ) * cos( radians(longitude) - radians('+my_long+') ) + sin( radians('+my_lat+') ) * sin( radians(latitude) ) ) ) <= 100')

где my_lat — вводная широта, my_long — вводная долгота, широта — поле модели для широты, долгота — поле модели для долготы, а 100 — расстояние.

Я использовал FloatField для широты и долготы в моей модели.

Теперь, когда это возвращает RawQueryset, если вам нужно работать с дополнительными фильтрами в наборе запросов, вы можете получить обычный набор запросов Django, выполнив:

      objects = YourModel.objects.filter(pk__in=[i.pk for i in objects])


Попробуйте этот код. я использую питон, sqlalchemy

этот запрос sqlalchemy возвращает ближайшие объекты в заданной точке. Он работает правильно. Но этот запрос возвращает все модели. Но он работает нормально.

мой модельный класс

#
class City(Base):
   __tablename__ = "tbl_City"
  city_id = Column(Integer, primary_key=True, unique=True) 
  geo_coordinates = Column(Geometry('POINT', srid=4326))

мой запрос

#
point = city.geo_coordinates
near_citylist = City.query.order_by(City.geo_coordinates.distance_box(point))

Я думаю, что лучший способ - использовать GeoDjango, как подсказывает Тимми, но тогда вам нужно использовать Geo-Backend (например, PosGis). Тем не менее, я не думаю, что это возможно использовать, если у вас есть модель, содержащая пользовательские поля широты и долготы, такие как

class CustomGeoModel(models.Model):
  lat = models.CharField(max_length=30)
  lon = models.CharField(max_length=30)
Другие вопросы по тегам