我正在尝试查询与Foo
具有多对多关系的模型Address
,其中地址将在距离给定点的指定距离内,并按升序距离对结果进行排序。看起来像注释就可以做到这一点但是我无法弄清楚如何在GeoDjango中做到这一点,因为它不支持地理注释。
这是我的基本模型结构:
# app name is bar
from django.contrib.gis.db import models
class Location(models.Model):
latlon = Models.PointFields(spatial_index=True)
# other fields ommitted
objects = models.GeoManager()
class Address(models.Model):
latlon = models.PointField(spatial_index=True)
# other fields omitted
objects = models.GeoManager()
class Foo(models.Model):
addresses = models.ManyToManyField(Address)
# other fields omitted
objects = models.GeoManager()
使用上述模型,我能够构建一个查询,选择所有Foo对象,这些对象的地址距离特定点的特定距离。例如:
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import Distance
new_york = Point(-73.98497, 40.75813) # == Location.latlon
Foo.objects.filter(addresses__latlon__distance_lte=(new_york, Distance(mi=20)))
生成类似以下内容的查询:
SELECT
"bar_foo"."id",
...
FROM "bar_foo"
INNER JOIN "bar_foo_address"
ON ("bar_foo"."id" = "bar_foo_address"."foo_id")
INNER JOIN "bar_address"
ON ("bar_foo_address"."address_id" = "bar_address"."id")
WHERE (ST_distance_sphere("bar_address"."latlon",ST_GeomFromEWKB(
'\x0101000020e6100000aaf1d24d628052c096218e75715b4440' :: BYTEA)) <= 32186.88)
这很有效,除非我遇到麻烦,如果我想根据他们与给定点的距离对所有foos进行排序。我试过像:
(Foo
.objects
.filter(addresses__latlon__distance_lte=(new_york, Distance(mi=20)))
.distance(Location.latlon)
.order_by('distance'))
# produces
TypeError: ST_Distance output only available on GeometryFields.
当我阅读一些源代码时,我试图修改查询但仍然出现错误:
(Foo
.objects
.filter(addresses__latlon__distance_lte=(new_york, Distance(mi=20)))
.distance(Location.latlon)
.order_by('distance', field_name='addresses_latlon'))
# produces
ValueError: <django.contrib.gis.db.models.fields.PointField: latlon> not in self.query.related_select_cols
我想这与Address
和Foo
具有多对多关系的事实有关。不幸的是,GeoDjango不支持常规注释,所以我不能做类似的事情:
# hypothetical syntax
(Foo
.objects
.annotate(distance=DistanceAnnotation('addresses__latlon', new_york, unit='mi'))
.filter(distance__lte=20)
.order_by('distance'))
# which would generate
SELECT
"bar_foo"."id",
(ST_distance_sphere("bar_address"."latlon",ST_GeomFromEWKB(
'\x0101000020e6100000aaf1d24d628052c096218e75715b4440' :: BYTEA)) as distance,
...
FROM "bar_foo"
INNER JOIN "bar_foo_address"
ON ("bar_foo"."id" = "bar_foo_address"."foo_id")
INNER JOIN "bar_address"
ON ("bar_foo_address"."address_id" = "bar_address"."id")
WHERE distance <= 32186.88)
ORDER BY distance ASC
所以问题是如何使用现有的API进行常规注释?或者也许其他一些方法我可以达到预期的效果?