我正努力让所有活动都在距离用户10英里的地方。我的模型看起来像这样:
class User(models.Model):
location = models.PointField()
...
class Event(models.Model):
location = models.PointField()
...
在我的测试中,当我检查用户与事件之间的距离时,我得到值11.5122663513
:
from geopy.distance import vincenty
print vincenty(request.user.location, event.location).miles # 11.5122663513
然而,当我查询用户所在位置10英里范围内的所有事件时,会返回该事件:
Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10))).count() # 1
只有当我将半径降低到4英里以下时,过滤器才会生效:
Event.objects.filter(location__distance_lte=(request.user.location, D(mi=3))).count() # 0
我几乎完全遵循docs' example,所以我认为我的查询不是问题。
可能导致这种差异的原因是什么?
答案 0 :(得分:2)
这在很大程度上取决于您使用的数据库类型。
因为笛卡尔数学比地理空间数学快得多,所以查询可能将坐标看作是在平面上而不是在球体上。
docs以这种方式解释:
大多数人都熟悉使用纬度和经度 参考地球表面的位置。但是,纬度和 经度是角度,而不是距离。换句话说,虽然 平面上两点之间的最短路径是直线, 曲面上两点之间的最短路径(如 地球)是一个大圆弧。因此,额外的计算 需要获得平面单位的距离(例如千米和米) 英里)。使用地理坐标系可能会引入 后来开发人员的并发症。例如,Spatialite可以 没有能力执行之间的距离计算 使用地理坐标系的几何形状,例如建造一个 查询以查找存储为县界的5英里范围内的所有点 WGS84。
地球表面的某些部分可能投射到二维面上, 或笛卡儿,飞机。特别是投影坐标系 方便区域特定的应用程序,例如,如果你知道 您的数据库只会覆盖北堪萨斯州的几何图形,那么您可以 考虑使用特定于该区域的投影系统。此外, 投影坐标系以笛卡尔单位定义(如 米或英尺),缓和距离计算。
此外,这可能会受到您的数据库选择的影响。如果您使用的是Postgres / PostGIS,则在文档中有以下注释:
在PostGIS中,ST_Distance_Sphere不限制几何类型 使用地理距离查询。但是,这些 查询可能需要很长时间,因为必须有大圆距离 为查询中的每一行动态计算。这是因为 传统几何字段的空间索引不能使用。
要在WGS84距离查询上获得更好的性能,请考虑使用 数据库中的地理列,因为他们能够 在距离查询中使用它们的空间索引。你可以告诉GeoDjango 通过在字段中设置geography = True来使用地理列 定义
您可以通过打印原始SQL来自行检查:
qs = Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10))
print qs.query
根据您的数据库类型以及您计划存储的数据量,您有几个选项:
geography=True
contains
如果您共享原始查询,则更容易弄清楚发生了什么。