Django 的 Distance 函数不返回 Distance 对象
Django's Distance function not returning a Distance object
这是在与@Nargiza 解决此问题的过程中出现的意外行为:。
在 Distance 函数 上关注 Django 文档:
Accepts two geographic fields or expressions and returns the distance between them, as a Distance object.
并且来自 Distance object, we can get the distance in each and every one of the 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
函数没有return一个Distance
对象?
这是一个错误,还是我们遗漏了什么?
提前感谢您的宝贵时间。
这两者并没有那么密切相关。文档确实说它是 "returns" 距离对象,但还有一个额外的步骤:
django.contrib.gis.db.models.functions.Distance 是一个 数据库 函数,它需要两个表达式(可能包括数据库字段名称)和 returns 一个 Func 对象,可以用作查询的一部分。
所以简单来说就是需要在数据库中执行。它将使用数据库函数(例如 postgis ST_Distance)计算距离,然后将其作为 django.contrib.gis.measure.Distance 对象返回。
所以,除非有人想弄乱 SQL 编译器和数据库连接,否则获取两点之间距离的最简单方法是 Distance(m=p1.distance(p2))
编辑: 一些代码来说明这一点:
您可以在 django/contrib/gis/measure.py 中查看距离(测量)class 的代码。它相当小且易于理解。它所做的只是为您提供一种方便的方法来进行距离的转换、比较和算术运算:
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"'
无聊。让我们使用 Distance 函数将距离值添加到结果中:
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
您需要将浮点数传递给过滤器,它将无法识别距离对象。
这是在与@Nargiza 解决此问题的过程中出现的意外行为:
在 Distance 函数 上关注 Django 文档:
Accepts two geographic fields or expressions and returns the distance between them, as a Distance object.
并且来自 Distance object, we can get the distance in each and every one of the 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
函数没有return一个Distance
对象?
这是一个错误,还是我们遗漏了什么?
提前感谢您的宝贵时间。
这两者并没有那么密切相关。文档确实说它是 "returns" 距离对象,但还有一个额外的步骤:
django.contrib.gis.db.models.functions.Distance 是一个 数据库 函数,它需要两个表达式(可能包括数据库字段名称)和 returns 一个 Func 对象,可以用作查询的一部分。
所以简单来说就是需要在数据库中执行。它将使用数据库函数(例如 postgis ST_Distance)计算距离,然后将其作为 django.contrib.gis.measure.Distance 对象返回。
所以,除非有人想弄乱 SQL 编译器和数据库连接,否则获取两点之间距离的最简单方法是 Distance(m=p1.distance(p2))
编辑: 一些代码来说明这一点:
您可以在 django/contrib/gis/measure.py 中查看距离(测量)class 的代码。它相当小且易于理解。它所做的只是为您提供一种方便的方法来进行距离的转换、比较和算术运算:
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"'
无聊。让我们使用 Distance 函数将距离值添加到结果中:
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
您需要将浮点数传递给过滤器,它将无法识别距离对象。