【问题标题】:Django order by Min Distance to a list of pointsDjango按最小距离排序到点列表
【发布时间】:2020-09-29 12:21:47
【问题描述】:

我想获取在给定距离内至少到许多提供位置之一的所有作业的查询集,按最小距离对它们进行排序,并且不显示重复的作业。

from django.db import models
from cities.models import City    

class Job(models.Model):
    title = models.CharField(max_length=255)
    cities = models.ManyToManyField(City)

如果只有一点我可以这样做:

from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import Point
point = Point(x, y, srid=4326)  
Job.objects.filter(cities__location__dwithin=(point, dist)) \
           .annotate(distance=Distance("cities__location", point) \
           .order_by('distance')

但是当我有很多点时,我为过滤器构建了一个 Q 表达式,但不确定一种干净的方式来注释作业到所有点的最小距离

query = Q()
for point in points:
    query |= Q(cities__location__dwithin=(point, dist))
Job.objects.filter(query).annotate(distance=Min(...)).order_by('distance')

仅供参考,使用带有 PostGIS 扩展的 postgres 12.1

【问题讨论】:

    标签: python django postgresql django-queryset postgis


    【解决方案1】:
    query = Q()
    distances = []
    for point in points:
        query |= Q(cities__location__dwithin=(point, dist))
        distances.append(Distance("cities__location", point))
    
    # LEAST requires 2 or more expressions, MIN works for single expression
    if len(distances) == 1:
        MIN_FUNC = Min
    else:
        MIN_FUNC = Least
    
    Job.objects.filter(query).annotate(distance=MIN_FUNC(*distances)).order_by('distance')
    
    • MIN 是一个聚合函数,它采用单个表达式,例如列名,并将多个输入减少为单个输出值
    • LEAST 是一个条件表达式,通过从任意数量的表达式列表中选择最小值来发挥作用

    https://docs.djangoproject.com/en/3.0/ref/models/querysets/#min https://docs.djangoproject.com/en/3.0/ref/models/database-functions/#least

    【讨论】: