2014-06-12 104 views
4

我有一个单一的PointField的地理模型,我期待添加一个注释的每个模型距离给定的点,我可以稍后过滤和做额外的jiggery pokery。如何添加从点作为注释距离作为GeoDjango

有明显的queryset.distance(to_point)函数,但它实际上并没有注释查询集,它只是为查询集中的每个模型添加一个距离属性,这意味着我不能在稍后将.filter(distance__lte=some_distance)应用于它。

我也知道过滤的领域,像这样保持距离:

queryset.filter(point__distance_lte=(to_point, D(mi=radius))) 

但因为我会想要做多个过滤器(不同的距离范围内获得的型号计数),我不真的不想让DB每次计算与给定点的距离,因为这可能会很昂贵。

任何想法?具体来说,是否有一种方法可以将此添加为常规注释而不是每个模型的插入属性?

回答

4

我无法找到这样做的任何方式烤,所以最后我刚刚创建了自己的聚合类:

这仅适用于post_gis,但让一个为另一个地理数据库不应该太棘手。

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)")) 

任何人都知道这样做的更好的方法,请让我知道(或告诉我为什么我的是愚蠢的)

+1

刘以达切割器,但是,同时注释点格式应该像下面 点= “POINT(1.022 -42.029)” 实施例:http://postgis.net/docs/ST_GeomFromText.html – naren

+0

Woops,良好的抓。更新。 –

+0

由于django 1.11'ImportError:没有名为aggregates的模块抛出。 –

2

您可以使用GeoQuerySet.distance

cities = City.objects.distance(reference_pnt) 
for city in cities: 
    print city.distance() 

Link: GeoDjango distance documentaion

编辑:随距离滤波器沿添加距离属性查询

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') 

Supported distance lookups

  • distance_lt
  • distance_lte
  • distance_gt
  • distance_gte
  • dwithin
+0

嘿,谢谢你的回答,但我在原始问题中提到过这个问题。不幸的是,它不允许在距离属性上使用.filter()。或者至少它以前似乎没有。如果我错误地认为那么请随时扩大你的答案,详细说明如何以这种方式使用它,如果我能重现,我会改变你的答案。 –

+0

@TomDickin我已经更新了几个例子,显示了距离查询和order_by。 – naren

+0

这将返回什么?有没有办法做这样的事情没有数据库? – Gocht

1

其中一种现代方法是设置“output_field”arg以避免«不正确的几何输入类型»。使用output_field django试图将ST_Distance_Sphere浮点结果转换为GEOField并且不能。

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' 
     ) 
    )