12

我有以下模型。

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 公里半径内的所有 Location 对象,我该如何过滤它,使其只返回 10 公里半径内的所有 Location 对象?

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

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

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

4

3 回答 3

13

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

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

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

于 2013-07-16T16:41:03.273 回答
12

但是您总是可以通过过滤上一步的结果(最好应该是较小的子集)来使 Brian 提出的方法更好,并为每个您检查它们是否在半径内。

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

在此处输入图像描述

更新:

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

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

于 2014-01-29T11:12:40.047 回答
3

如果你不想使用 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)
于 2019-08-27T18:45:39.447 回答