Django distance function does not return a distance object

This is an unexpected behavior that came up in solving this problem with @Nargiza: 3D distance calculations with GeoDjango .

Following the Django docs in the Distance function :

It takes two geographical fields or expressions, and returns the distance between them as an object of distance .

And from the Distance object , we can get the distance in each of the supported devices .

But:

Let the model be:

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

then the following:

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

should print the distance between p1and p2in meters.

Instead, we got the following error:

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

(d = Distance(m=p1.distance(p2))), :

Distance Distance ?
, - ?

.

+3
1

. , "" "", :

django.contrib.gis. db.models.functions.Distance - , ( ) a Func, .

, . (, postgis ST_Distance), django.contrib.gis.measure.Distance.

, SQL db, - Distance(m=p1.distance(p2))

: :

Distance () 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

Distance:

__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"'

, ST_distance_sphere sql, , "mymodel"."coordinates" origin.

, ():

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 ​​, Distance.

+2

Source: https://habr.com/ru/post/1683452/


All Articles