使用距离逻辑 这个帖子, ,我使用以下代码返回一组经过正确过滤的对象:

class LocationManager(models.Manager):
    def nearby_locations(self, latitude, longitude, radius, max_results=100, use_miles=True):
        if use_miles:
            distance_unit = 3959
        else:
            distance_unit = 6371

        from django.db import connection, transaction
        cursor = connection.cursor()

        sql = """SELECT id, (%f * acos( cos( radians(%f) ) * cos( radians( latitude ) ) *
        cos( radians( longitude ) - radians(%f) ) + sin( radians(%f) ) * sin( radians( latitude ) ) ) )
        AS distance FROM locations_location HAVING distance < %d
        ORDER BY distance LIMIT 0 , %d;""" % (distance_unit, latitude, longitude, latitude, int(radius), max_results)
        cursor.execute(sql)
        ids = [row[0] for row in cursor.fetchall()]

        return self.filter(id__in=ids)

问题是我不知道如何保持列表/查询集按距离值排序。出于性能原因(一个查询与数据库中每个潜在位置的一个查询),我不想将其作为 extra() 方法调用来执行。有几个问题:

  1. 如何按距离对列表进行排序?即使取消我在模型中定义的本机排序并使用“order_by()”,它仍然按其他内容(我相信 id)进行排序。
  2. 我对性能的看法是否错误,Django 会优化查询,所以我应该使用 extra() 代替?
  3. 这是完全错误的方法吗?我应该使用地理库,而不是像普茨一样手动滚动它?
有帮助吗?

解决方案

要以相反的顺序回答您的问题:

Re 3) 是的,如果您正在处理地理空间数据,您绝对应该利用 PostGIS 和 GeoDjango。不这样做真是愚蠢。

Re 2)我认为你不能完全让 Django 使用 .extra() 为你做这个查询(除非接受 这张票),但它是 Django 1.2 中新的 .raw() 方法的绝佳候选者(见下文)。

回复 1) 您将从第一个查询中获取 id 列表,然后使用“in”查询来获取与这些 id 对应的对象的 QuerySet。您的第二个查询无法访问第一个查询计算出的距离;它只是获取 id 列表(并且它也不关心您提供这些 id 的顺序)。

可能的解决方案(除了放弃所有这些并使用 GeoDjango):

  1. 升级到 Django 1.2 beta 并使用 新的 .raw() 方法. 。这使得 Django 能够智能地解释原始 SQL 查询的结果并将其转换为实际模型对象的查询集。这会将当前的两个查询减少为一个,并保留您在 SQL 中指定的顺序。如果您能够进行升级,这是最好的选择。

  2. 根本不用费心构建 Django 查询集或 Django 模型对象,只需将所需的所有字段添加到原始 SQL SELECT 中,然后直接从游标使用这些行即可。如果您稍后需要模型方法等,可能不是一个选择。

  3. 在 Python 代码中执行第三步,迭代查询集并按照与从第一个查询返回的 ids 列表相同的顺序构造模型对象的 Python 列表。返回该列表而不是查询集。如果您需要进一步过滤,则不起作用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top