我尝试使用Django 2.0.3和PostGIS(GeoDjango)函数使用最近的Station
的{{1}}来注释id
的查询集。
简化Station
型号:
Station
我遇到的问题是尝试计算最近距离,这涉及注释引用外部查询集中class Station(models.Model):
name = models.CharField(max_length=128)
location = models.PointField()
objects = StationQuerySet.as_manager()
的子查询。
location
行from django.db.models import OuterRef, Subquery
from django.contrib.gis.db.models.functions import Distance
class StationQuerySet(models.QuerySet):
def add_nearest_neighbour(self):
'''
Annotates each station with the id and distance of the nearest neighbouring station
'''
# Get Station model
Station = self.model
# Calculate distances to each station in subquery
subquery_with_distance = Station.objects.annotate(distance=Distance('location', OuterRef('location')) / 1000)
# Get nearest from subquery
nearest = subquery_with_distance.order_by('distance').values('id')[0]
return self.annotate(
nearest_station_id=Subquery(nearest)
)
会导致以下错误:
distance = Station.objects.annotate(distance=Distance('location', OuterRef('location')) / 1000)
错误:
from apps.bikeshare.models import Station
stations = Station.objects.add_nearest_neighbour()
答案 0 :(得分:0)
想出了一个使用原始查询来查找最近的工作站的工作,并从子查询中选择id和距离,下面是奖励说明:
class StationQuerySet(models.QuerySet):
def nearest_neighbour(self):
'''
Creates a RawQuerySet of each station with the id and distance of the nearest neighbouring station
'''
# Have to execute the query in order to get the list of ids to inject
ids = tuple(self.values('id').values_list('id', flat=True))
return self.raw('''
SELECT
A0.id as id,
SUB.closest_id,
SUB.closest_distance
FROM "bikeshare_station" A0
CROSS JOIN LATERAL (
SELECT
B0.id as closest_id,
st_distance_sphere(A0.location, B0.location) as closest_distance
FROM "bikeshare_station" B0
WHERE A0.id != B0.id
ORDER BY A0.location <-> B0.location
limit 1
) SUB
WHERE A0.id IN %s;
''', [ids])
您可以将查询集调用链接在一起以在查找最近邻居之前过滤查询集:
query = Station.objects.filter(name='Albert Gate, Hyde Park')
closest_stations = query.nearest_neighbour()
station = closest_stations[0]
station.name
[out]: 'Albert Gate, Hyde Park'
station.closest_distance
[out]: 133.52459069
station.closest_id
[out]: 6369
此类子查询称为相关子查询,因为它引用外部查询中的列。此外,我需要选择有关最近的电台的多条信息(id
,distance
等)。
子查询放在FROM
子句中,允许选择多个列。需要LATERAL
连接以允许子查询引用FROM
列表中的兄弟表。通过子查询返回单行,可以应用CROSS
连接以基于笛卡尔积而不是共享列来形成连接表。
子查询使用PostGIS <->
运算符,它可以更有效地按工作站之间的距离对表格进行排序,并st_distance_sphere
在点之间进行精确的距离计算。