如何使用落在某个半径范围内的纬度和经度坐标过滤django模型

时间:2013-07-16 16:35:38

标签: python django haversine

我有以下型号。

class Location(models.Model):
    name = models.CharField(max_length = 128, blank = True)
    address =models.CharField(max_length = 200, blank= True)
    latitude = models.DecimalField(max_digits=6, decimal_places=3)
    longitude = models.DecimalField(max_digits=6, decimal_places=3)

    def __unicode__(self):
        return self.name

如果我目前的纬度&经度是:

current_lat = 43.648
current_long = 79.404

我做了一些研究并遇到了Haversine Equation,它计算了两个位置坐标之间的距离。以下是我发现的等式:

import math

def distance(origin, destination):
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371 # km

    dlat = math.radians(lat2-lat1)
    dlon = math.radians(lon2-lon1)
    a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
        * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    d = radius * c

    return d

我想返回半径10公里范围内的所有位置对象,如何过滤它只会返回落在这10公里范围内的所有位置对象?

LocationsNearMe = Location.objects.filter(#This is where I am stuck)

无论如何,我可以将Haversine方程实现到滤波中,以便它只返回半径10公里范围内的位置对象吗?

我正在寻找一个详尽的答案。感谢帮助。

3 个答案:

答案 0 :(得分:10)

您可以使用filter进行范围查询。

LocationsNearMe = Location.objects.filter(latitude__gte=(the minimal lat from distance()),
                                          latitude__lte=(the minimal lat from distance()),
                                          (repeat for longitude))

不幸的是,这会以几何方形(而不是圆形)的形式返回结果

答案 1 :(得分:8)

但是你总是可以通过过滤前一步骤的结果(这应该是较小的子集)来更好地通过Brian方法提出建议,并且每次检查它们是否在半径范围内。

您的用户处于黑点。 Brian给出的平方近似值返回绿色,但也返回橙色点。在最坏的情况下,距离的差异可能是显着的,用户必须比预期的更多(比额外的40%)达到sqrt(2)倍。因此,对于所有橙色和绿色点,有必要检查它们与黑点的距离(例如,如果这是真正的短距离,如城市中的导航,则为欧几里德)不大于假定的半径。

enter image description here

更新:

如果您想使用Haversine距离或(更好)提到GeoDjango hava,请查看此片段,比较处理附近搜索的两个django视图:

https://gist.github.com/andilabs/4232b463e5ad2f19c155

答案 2 :(得分:2)

如果您不想使用GeoDjango,则可以考虑使用Django的Database functions进行编写。与原始SQL相比,这还为您提供了能够轻松附加/添加其他ORM过滤器的优势。

from django.db.models.functions import Radians, Power, Sin, Cos, ATan2, Sqrt, Radians
from django.db.models import F

dlat = Radians(F('latitude') - current_lat)
dlong = Radians(F('longitude') - current_long)

a = (Power(Sin(dlat/2), 2) + Cos(Radians(current_lat)) 
    * Cos(Radians(F('latitude'))) * Power(Sin(dlong/2), 2)
)

c = 2 * ATan2(Sqrt(a), Sqrt(1-a))
d = 6371 * c

LocationsNearMe = Location.objects.annotate(distance=d).order_by('distance').filter(distance__lt=10)