如何在GeoDjango中将距点的距离添加为注释
我有一个带有单点域的地理模型,我希望为每个模型到给定点的距离添加一个注释,我可以在以后进行过滤并进行额外的拼凑 有一个明显的如何在GeoDjango中将距点的距离添加为注释,django,django-models,postgis,geodjango,Django,Django Models,Postgis,Geodjango,我有一个带有单点域的地理模型,我希望为每个模型到给定点的距离添加一个注释,我可以在以后进行过滤并进行额外的拼凑 有一个明显的queryset.distance(to_point)函数,但它实际上并没有注释queryset,它只是向queryset中的每个模型添加了一个distance属性,这意味着我以后无法对其应用.filter(distance_ulte=some_distance) 我也知道通过字段和距离本身进行过滤,如下所示: queryset.filter(point__distance
queryset.distance(to_point)
函数,但它实际上并没有注释queryset,它只是向queryset中的每个模型添加了一个distance属性,这意味着我以后无法对其应用.filter(distance_ulte=some_distance)
我也知道通过字段和距离本身进行过滤,如下所示:
queryset.filter(point__distance_lte=(to_point, D(mi=radius)))
但是,由于我想做多个过滤器(以获得不同距离范围内的模型计数),我真的不想让DB每次都计算到给定点的距离,因为这可能会很昂贵
有什么想法吗?具体来说,是否有办法将其添加为常规注释而不是每个模型的插入属性?我找不到任何烘焙方法,因此最后我创建了自己的聚合类: 这只适用于post_gis,但为另一个geo db创建一个也不太复杂
from django.db.models import Aggregate, FloatField
from django.db.models.sql.aggregates import Aggregate as SQLAggregate
class Dist(Aggregate):
def add_to_query(self, query, alias, col, source, is_summary):
source = FloatField()
aggregate = SQLDist(
col, source=source, is_summary=is_summary, **self.extra)
query.aggregates[alias] = aggregate
class SQLDist(SQLAggregate):
sql_function = 'ST_Distance_Sphere'
sql_template = "%(function)s(ST_GeomFromText('%(point)s'), %(field)s)"
这可以按如下方式使用:
queryset.annotate(distance=Dist('longlat', point="POINT(1.022 -42.029)"))
如果有人知道更好的方法,请告诉我(或者告诉我为什么我的方法很愚蠢)您可以使用GeoQuerySet.distance
cities = City.objects.distance(reference_pnt)
for city in cities:
print city.distance()
编辑:添加距离属性和距离过滤器查询
usr_pnt = fromstr('POINT(-92.69 19.20)', srid=4326)
City.objects.filter(point__distance_lte=(usr_pnt, D(km=700))).distance(usr_pnt).order_by('distance')
- 距离
- 距离
- 距离
- 距离
- 德威辛
queryset = self.objects.annotate(
distance=Func(
Func(
F('addresses__location'),
Func(
Value('POINT(1.022 -42.029)'),
function='ST_GeomFromText'
),
function='ST_Distance_Sphere',
output_field=models.FloatField()
),
function='round'
)
)
一种注释和排序的方法w/out GeoDjango。该模型包含坐标记录的外键,该坐标记录包含lat和lng属性
def get_nearby_coords(lat, lng, max_distance=10):
"""
Return objects sorted by distance to specified coordinates
which distance is less than max_distance given in kilometers
"""
# Great circle distance formula
R = 6371
qs = Precinct.objects.all().annotate(
distance=Value(R)*Func(
Func(
F("coordinates__lat")*Value(math.sin(math.pi/180)),
function="sin",
output_field=models.FloatField()
) * Value(
math.sin(lat*math.pi/180)
) + Func(
F("coordinates__lat")* Value(math.pi/180),
function="cos",
output_field=models.FloatField()
) * Value(
math.cos(lat*math.pi/180)
) * Func(
Value(lng*math.pi/180) - F("coordinates__lng") * Value(math.pi/180),
function="cos",
output_field=models.FloatField()
),
function="acos"
)
).order_by("distance")
if max_distance is not None:
qs = qs.filter(distance__lt=max_distance)
return qs
这样做对我很有用(我可以在注释上应用过滤器)。 为了可读性而分解
from models import Address
from django.contrib.gis.measure import D
from django.contrib.gis.db.models.functions import Distance
intMiles = 200
destPoint = Point(5, 23)
queryset0 = Address.objects.all().order_by('-postcode')
queryset1 = queryset0.annotate(distance=Distance('myPointField' , destPoint ))
queryset2 = queryset1.filter(distance__lte=D(mi=intMiles))
希望它能帮助一些人:)Tats CLIVER,但是在注释点格式时应该像下面的point=“point(1.022-42.029)”示例:从django 1.11开始,没有名为aggregates的模块抛出。2020年有现成的解决方案吗?嘿,谢谢你的回答,但我在原始问题中提到了这一点。不幸的是,它不允许在距离属性上使用.filter()。或者至少它以前似乎没有。如果我的想法不正确,请随意扩展您的答案,详细说明如何以这种方式使用,如果我可以复制,我会将您的答案更改为可接受的答案。@TomDickin我更新了几个示例,显示了距离查询和顺序。这将返回什么?有没有一种方法可以在没有DB的情况下执行类似的操作?如何将
srid=4326
传递到点
?