2014-06-12 106 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' 
     ) 
    )