【问题标题】:Sort results by distance and get the distance between them and the query point按距离对结果进行排序,得到与查询点的距离
【发布时间】:2017-09-07 23:54:12
【问题描述】:

我目前使用以下方法按距离对模型的结果进行排序:

views.py

    SearchPoint = Point(long, lat)    
    res = Model.objects.filter(location__distance_lte=(SearchPoint, D(m=2000)))
               .annotate(distance=Distance('location', SearchPoint))
               .order_by('distance')

这允许我将 2000m 内的结果按distance 排序。

现在我还想显示SearchPoint 给出的搜索者与我的Model 的结果之间的距离。

Models.py 在我的模型类中,我定义了以下属性:

@property
def distance_to_searcher(self):
    distance =self.location.distance(SearchPoint)
    return distance * 100

但我收到以下错误:

名称“搜索点”未定义

我知道这没有定义,因为它是在 views.py 文件中定义的,这是一个 GET 请求,从 URL 中获取 long 和 lat 参数并将它们放入 Point() 类中。

理想情况下,我会将距离四舍五入到一个不错的数字。

编辑:我在 views.py

中定义了SearchPoint
def get_context_data(self, **kwargs):
    if self.request.method == 'GET':
        form = LocationForm(self.request.GET)
        if form.is_valid():
            SearchPoint=Point(form.cleaned_data['Lng'],form.cleaned_data['Lat'])
        else:
            form = LocationForm()
            SearchPoint=Point(0,0)

【问题讨论】:

    标签: python django geodjango


    【解决方案1】:

    由于您正在创建此查询:

    res = Model.objects.filter(location__distance_lte=(SearchPoint, D(m=2000)))
                       .annotate(distance=Distance('location', SearchPoint))
                       .order_by('distance')
    

    通过使用annotate,您正在向查询返回的每个模型对象“添加”一个名为distance 的字段。

    也就是说,如果你这样做:

    for item in res:
        print(item.distance)
    

    你会得到每个模型对象到SearchPoint的距离。


    如果您绝对想在模型中使用 @property,则应以接受 SearchPoint 作为参数的方式定义它:

    @property
    def distance_to_searcher(self, search_point):
        distance=self.location.distance(search_point)
        return distance * 100
    

    但您也必须修改您的查询:

    res = Model.objects.filter(location__distance_lte=(SearchPoint, D(m=2000)))
                       .order_by('distance')
    

    因为您不再需要使用 annotate 在查询集中创建 distance 字段。
    现在如果你这样做:

    for item in res:
        print(item.distance_to_searcher(SearchPoint))
    

    你会得到和上面一样的结果。

    【讨论】:

    • 谢谢,还有一件事。似乎在模板中,它会自动计算m和float的距离。我如何用km四舍五入到小数点后1位?我尝试使用 res.distance|floatformat:0 ,但它似乎是一个字符串而不是数字。
    • @Roma 您可以操作distance 字段以返回以km 为单位的Distance,您可以更改视图返回的内容,以便在模板中而不是在模板中格式化浮动! (搜索并尝试这些,如果您仍然有问题,您可以在 SO 上发另一个帖子与您的问题)
    【解决方案2】:

    我发现解决方案只需在我的模板中调用.distanceres 变量已经有距离作为属性,不需要额外的属性。

    【讨论】: