我在Django中使用GeopositionField来存储用户的坐标。现在我想找到最接近当前用户的20个用户的列表。我的GeopositionField可以实现该功能吗?我知道GeoDjango可以轻松搜索距离,但由于我使用Heroku和postgresql,我想降低成本并使用postgressql,安装PostGIS似乎是唯一的选择。
有什么建议吗?
答案 0 :(得分:8)
对于两点之间的距离,您可以使用Geopy。
来自documetation: 以下是distance.distance的示例用法:
>>> from geopy import distance
>>> _, ne = g.geocode('Newport, RI')
>>> _, cl = g.geocode('Cleveland, OH')
>>> distance.distance(ne, cl).miles
538.37173614757057
在Django项目中实现这一点。在models.py中创建一个普通模型:
class User(models.Model):
name = models.Charfield()
lat = models.FloatField()
lng = models.FloatField()
要优化一点,您可以过滤用户对象,以便首先粗略估计附近的用户。这样您就不必遍历db中的所有用户。这种粗略估计是可选的。为了满足您的所有项目要求,您可能需要编写一些额外的逻辑:
#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()
计算用户与用户中每个用户之间的距离,按距离对其进行排序并获得前20个。
results = []
for user in users:
d = distance.distance((lat, lng), (user.lat, user.lng))
results.append( {'distance':d, 'user':user })
results = sorted(results, key=lambda k: k['distance'])
results = results[:20]
答案 1 :(得分:1)
我认为你有两个选择:
没有空间索引(Postgis和Geodjango使用PointField)和使用GeopositionField,没有有效的方法。我发现处理这个问题的唯一方法是:
GeopositionField将坐标存储为文本,但可以使用字段上的.latitude
和longitude
进行检索。
似乎支持Postgresql 9.1+(http://wiki.postgresql.org/images/4/46/Knn.pdf)中的K-Nearest-Neighbors问题。但是,我认为您必须在表中添加另一列以存储点(http://www.postgresql.org/docs/9.2/static/datatype-geometric.html)或为GeopositionField实现距离函数。
如果您正在使用Heroku的基本设置进行开发并计划更改为更高的计划,我建议使用第一种方法,因为其他heroku计划支持Postgis,您可以轻松实现此方法,然后将其更改为一个简单的Postgis函数调用。
虽然,如果这是您处理空间数据的唯一情况,我建议使用Point字段和KNN支持。所以你将来不需要postgis支持。
答案 2 :(得分:0)
在源代码中快速浏览一下,显示GeopositionField
只将coördinates存储为纯文本(<latitude>,<longitude>
),因此无法从数据库中提取正确的数据。如果您想要高效的数据库查询,则必须使用GeoDjango或PostGIS(或找到另一种提供空间数据搜索的替代方案)。