2017-05-09 12 views
3

これは、@ Nargiza:3d distance calculations with GeoDjangoでこの問題を解決するための道のりに思いがけない動作です。DjangoのDistance関数がDistanceオブジェクトを返さない

Distance機能上のDjangoのドキュメントに続き:

Accepts two geographic fields or expressions and returns the distance between them, as a Distance object.

そしてDistanceオブジェクトから、我々はsupported unitsの一つ一つに距離を得ることができます。

しかし:

レッツモデルがあること:

class MyModel(models.Model): 
    ... 
    coordinates = models.PointField() 

次:

p1 = MyModel.objects.get(id=1).coordinates 
p2 = MyModel.objects.get(id=2).coordinates 
d = Distance(p1, p2) # This is the function call, 
        # so d should be a Distance object 
print d.m 

p1やメートルでp2間の距離を印刷する必要があります。

代わりに、我々は次のエラーました:

AttributeError: 'Distance' object has no attribute 'm' 

我々は最終的には回避策を見つけた(d = Distance(m=p1.distance(p2))を)が、疑問は残る:

はなぜDistance機能Distanceオブジェクトが返されませんでした
これはバグですか、それとも不足していますか?

お時間をいただきありがとうございます。

答えて

2

これらの2つは、互いに密接に関連しているわけではありません。ドキュメントは実際に距離オブジェクトを返すと言いますが、余分なステップがあります:

django.contrib.gis。 db.models .functions.Distanceは、データベース関数であり、2つの式(データベースフィールド名を含む可能性があります)を受け取り、クエリの一部として使用できるFuncオブジェクトを返します。

単純に言えば、データベース内で実行する必要があります。データベース機能(例:postgis ST_Distance)を使用して距離を計算し、django.contrib.gis.measure.Distanceオブジェクトとして戻します。あなたがチェックすることができ

1は、SQLコンパイラとDBの接続を台無しに望んでない限り、2点間の距離を取得する最も簡単な方法は、Distance(m=p1.distance(p2))

EDITです:ポイントを説明するためにいくつかのコード距離(測定)クラスのアウトコードはdjango/contrib/gis/measure.pyです。それはかなり小さく、理解しやすいです。それはやっているすべてはあなたの距離に変換、比較および算術演算を行うための便利な方法を与えている:

In [1]: from django.contrib.gis.measure import Distance 

In [2]: d1 = Distance(mi=10) 

In [3]: d2 = Distance(km=15) 

In [4]: d1 > d2 
Out[4]: True 

In [5]: d1 + d2 
Out[5]: Distance(mi=19.32056788356001) 

In [6]: _.km 
Out[6]: 31.09344 

それでは、距離関数を見てみましょう:

がモデルに__str__メソッドを追加しますのでそれはクエリセットAPIと短いDB_Tableの名によって返されたときに我々は、クエリで見ることができるように距離値を見ることができます:

class MyModel(models.Model): 
    coordinates = models.PointField() 

    class Meta: 
     db_table = 'mymodel' 

    def __str__(self): 
     return f"{self.coordinates} {getattr(self, 'distance', '')}" 

は、いくつかのオブジェクトを作成し、簡単なselect * fromクエリを実行します。

In [7]: from gisexperiments.models import MyModel 

In [8]: from django.contrib.gis.geos import Point 

In [10]: some_places = MyModel.objects.bulk_create(
    ...:  MyModel(coordinates=Point(i, i, srid=4326)) for i in range(1, 5) 
    ...:) 

In [11]: MyModel.objects.all() 
Out[11]: <QuerySet [<MyModel: SRID=4326;POINT (1 1) >, <MyModel: SRID=4326;POINT (2 2) >, <MyModel: SRID=4326;POINT (3 3) >, <MyModel: SRID=4326;POINT (4 4) >]> 

In [12]: str(MyModel.objects.all().query) 
Out[12]: 'SELECT "mymodel"."id", "mymodel"."coordinates" FROM "mymodel"' 

ボーリング。結果に距離値を追加するには、距離関数を使用してみましょう:

In [14]: from django.contrib.gis.db.models.functions import Distance 

In [15]: from django.contrib.gis.measure import D # an alias 

In [16]: q = MyModel.objects.annotate(dist=Distance('coordinates', origin)) 

In [17]: list(q) 
Out[17]: 
[<MyModel: SRID=4326;POINT (1 1) 157249.597768505 m>, 
<MyModel: SRID=4326;POINT (2 2) 314475.238061007 m>, 
<MyModel: SRID=4326;POINT (3 3) 471652.937856715 m>, 
<MyModel: SRID=4326;POINT (4 4) 628758.663018087 m>] 

In [18]: str(q.query) 
Out[18]: 'SELECT "mymodel"."id", "mymodel"."coordinates", ST_distance_sphere("mymodel"."coordinates", ST_GeomFromEWKB(\'\\001\\001\\000\\000 \\346\\020\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\'::bytea)) AS "distance" FROM "mymodel"' 

あなたはそれが私たちのoriginポイントの"mymodel"."coordinates"とバイト表現からの値を使用して距離を計算しますST_distance_sphere SQL関数を使用して見ることができます。

我々は今、すべてのデータベース管理システム(速い)の内側に、フィルタリングや順序や他のものの多くのためにそれを使用することができます

In [19]: q = q.filter(distance__lt=D(km=400).m) 

In [20]: list(q) 
Out[20]: 
[<MyModel: SRID=4326;POINT (1 1) 157249.597768505 m>, 
<MyModel: SRID=4326;POINT (2 2) 314475.238061007 m>] 

お知らせ.mあなたはそれを獲得した、フィルターにフロート番号を渡す必要があるが距離オブジェクトを認識することはできません。

+0

答えにいくつかのコードを追加する必要があるかどうかを教えてください。私はしたいが、何かを最小限にするために苦労した。後でもう一度試してみます – Igonato

+0

@Igonatoさん、ありがとうございました。いいですね。私は他の応答の場合に恩恵を保つでしょう:) –

+0

@ JohnMoutafisはいくつかのコードを追加しました。私はGeoDjangoにはかなり新しいです、それを説明する良い方法があるかもしれませんが、これは私のベストです。また、エラーを修正しました。関数距離は、LookupオブジェクトではなくFuncを返します – Igonato

関連する問題