Python Django:子查询上的注释

Python Django:子查询上的注释,python,django,subquery,geodjango,Python,Django,Subquery,Geodjango,我正试图使用Django 2.0.3和PostGIS(GeoDjango)函数,用最近相邻的站的id对站的查询集进行注释 简化的站点模型: class Station(models.Model): name = models.CharField(max_length=128) location = models.PointField() objects = StationQuerySet.as_manager() 我遇到的问题是试图计算最近距离,这涉及到注释一个子查询,

我正试图使用Django 2.0.3和PostGIS(GeoDjango)函数,用最近相邻的
站的
id
站的查询集进行注释

简化的
站点
模型:

class Station(models.Model):
    name = models.CharField(max_length=128)
    location = models.PointField()
    objects = StationQuerySet.as_manager()
我遇到的问题是试图计算最近距离,这涉及到注释一个子查询,该子查询引用外部查询集中的
位置

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.annotation(distance=distance('location',OuterRef('location'))/1000)
导致如下所示的错误:

from apps.bikeshare.models import Station
stations = Station.objects.add_nearest_neighbour()
错误:

Traceback (most recent call last):
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/IPython/core/interactiveshell.py", line 2847, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-3-cb35ea6d5d8b>", line 1, in <module>
    stations = Station.objects.add_nearest_neighbour()
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/gbrown/Development/transit_bikeshare/apps/bikeshare/querysets.py", line 162, in add_nearest_neighbour
    subquery_with_distance = Station.objects.annotate(distance=Distance('location', OuterRef('location')) / 1000)
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/query.py", line 997, in annotate
    clone.query.add_annotation(annotation, alias, is_summary=False)
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/sql/query.py", line 975, in add_annotation
    summarize=is_summary)
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/expressions.py", line 452, in resolve_expression
    c.lhs = c.lhs.resolve_expression(query, allow_joins, reuse, summarize, for_save)
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/contrib/gis/db/models/functions.py", line 58, in resolve_expression
    source_fields = res.get_source_fields()
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/expressions.py", line 349, in get_source_fields
    return [e._output_field_or_none for e in self.get_source_expressions()]
  File "/home/gbrown/Envs/bikeshare-dev/lib/python3.5/site-packages/django/db/models/expressions.py", line 349, in <listcomp>
    return [e._output_field_or_none for e in self.get_source_expressions()]
AttributeError: 'ResolvedOuterRef' object has no attribute '_output_field_or_none'
回溯(最近一次呼叫最后一次):
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/IPython/core/interactiveshell.py”,第2847行,运行代码
exec(代码对象、self.user\u全局、self.user\n)
文件“”,第1行,在
stations=Station.objects.add_nearest_Neighbor()
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/manager.py”,第82行,在manager_方法中
返回getattr(self.get_queryset(),name)(*args,**kwargs)
文件“/home/gbrown/Development/transit_bikeshare/apps/bikeshare/querysets.py”,第162行,添加最近邻
子查询带有距离=Station.objects.annotate(距离=距离('location',OuterRef('location'))/1000)
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/manager.py”,第82行,在manager_方法中
返回getattr(self.get_queryset(),name)(*args,**kwargs)
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/query.py”,第997行,注释中
clone.query.add_注释(注释,别名,is_summary=False)
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/sql/query.py”,第975行,添加注释
summary=is_summary)
解析表达式中的文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/expressions.py”,第452行
c、 lhs=c.lhs.resolve_表达式(查询、允许_连接、重用、汇总、保存)
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/contrib/gis/db/models/functions.py”,第58行,解析表达式
source\u fields=res.get\u source\u fields()
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/expressions.py”,第349行,在get\u source\u字段中
在self.get\u source\u expressions()中为e返回[e.\u output\u field\u或\u none]
文件“/home/gbrown/Envs/bikeshare dev/lib/python3.5/site packages/django/db/models/expressions.py”,第349行,在
在self.get\u source\u expressions()中为e返回[e.\u output\u field\u或\u none]
AttributeError:“ResolvedOutRef”对象没有属性“\u输出\u字段\u或\u无”

提出了一个解决方案,使用原始查询查找最近的站点,并选择子查询的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])
SQL解释 这种类型的子查询称为相关子查询,因为它引用外部查询中的列。此外,我需要选择关于最近车站的多条信息(
id
距离
,等等)

子查询位于
FROM
子句中,该子句允许选择多个列。需要一个
LATERAL
联接,以允许子查询引用
FROM
列表中的同级表。当子查询返回单行时,可以应用
交叉
联接,以基于笛卡尔积而不是共享列形成联接表


子查询使用PostGIS
运算符,该运算符在按站点之间的距离对表进行排序时效率更高,并且使用
st\u distance\u sphere
,要在点之间进行精确的距离计算。

提出了一个解决方案,使用原始查询查找最近的桩号,并从子查询中选择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])
SQL解释 这种类型的子查询称为相关子查询,因为它引用外部查询中的列。此外,我需要选择关于最近车站的多条信息(
id
距离
,等等)

子查询位于
FROM
子句中,该子句允许选择多个列。需要一个
LATERAL
联接,以允许子查询引用
FROM
列表中的同级表。当子查询返回单行时,可以应用
交叉
联接,以基于笛卡尔积而不是共享列形成联接表


子查询使用PostGIS
运算符,该运算符在按站点之间的距离对表进行排序时效率更高,并且使用
st\u distance\u sphere
,要在点之间进行精确的距离计算。

你能发布完整的堆栈跟踪吗?@solarissmoke我已经更新了问题,将完整堆栈跟踪包括在内。在某个点指向外键的子查询/outerrefs周围有一个bug。我想知道这个查询集现在是否可以工作……你能发布完整的堆栈跟踪吗?@solarismoke我已经更新了这个问题,将完整的堆栈跟踪包括在内。在某个点指向外键的子查询/outerrefs周围有一个bug。我想知道这个查询集现在是否可以工作……是的,在ORM中进行横向连接是不可能的。这当然是我想要的。是的,在ORM中做横向连接是不可能的。这当然是我想要的东西。