Django:子查询的注释

2024-09-26 18:17:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使用Django 2.0.3和PostGIS(GeoDjango)函数,用最近相邻的Station的{}来注释{}的查询集。在

简化Station模型:

class Station(models.Model):
    name = models.CharField(max_length=128)
    location = models.PointField()
    objects = StationQuerySet.as_manager()

我遇到的问题是试图计算最近距离,这涉及到注释引用外部查询集中的location的子查询。在

^{pr2}$

distance = Station.objects.annotate(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'

Tags: djangoinpydevhomemodelslibpackages
1条回答
网友
1楼 · 发布于 2024-09-26 18:17:46

想出了一个解决办法,使用原始查询查找最近的电台,并从子查询中选择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])

使用

您可以将querysets调用链接在一起,以便在查找最近的邻居之前筛选queryset:

^{pr2}$

SQL解释

这种类型的子查询称为相关子查询,因为它引用外部查询中的列。另外,我需要选择关于最近的站点的多条信息(iddistance,等等)。在

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

子查询使用PostGIS <->运算符和st_distance_sphere运算符来精确计算点之间的距离,该运算符在按站点之间的距离排序时效率更高。在

相关问题 更多 >

    热门问题