Django 按计算字段排序
Posted
技术标签:
【中文标题】Django 按计算字段排序【英文标题】:Django Sort By Calculated Field 【发布时间】:2010-02-16 19:09:48 【问题描述】:使用来自this SO post 的距离逻辑,我将使用以下代码返回一组经过适当过滤的对象:
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() 方法调用(一个查询与对我数据库中每个潜在位置的一个查询)来执行此操作。几个问题:
-
如何按距离对列表进行排序?即使取消我在模型中定义的本机排序并使用“order_by()”,它仍然按其他方式排序(id,我相信)。
我对性能问题有误吗,Django 会优化查询,所以我应该改用 extra() 吗?
这是完全错误的方法吗?我应该使用地理库而不是像 putz 一样手动滚动它?
【问题讨论】:
【参考方案1】:以相反的顺序回答您的问题:
Re 3) 是的,如果您使用地理空间数据,您绝对应该利用 PostGIS 和 GeoDjango。不这样做是愚蠢的。
Re 2) 我不认为您可以让 Django 使用 .extra() 为您执行此查询(除非接受 this ticket),但它是新的 .raw() 方法的绝佳候选者在 Django 1.2 中(见下文)。
Re 1)您从第一个查询中获取 id 列表,然后使用“in”查询获取与这些 id 对应的对象的 QuerySet。您的第二个查询无法访问与第一个查询的计算距离;它只是获取一个 id 列表(它也不关心您提供这些 id 的顺序)。
可能的解决方案(放弃所有这些并使用 GeoDjango):
升级到 Django 1.2 beta 并使用 new .raw() method。这允许 Django 智能地解释原始 SQL 查询的结果并将其转换为实际模型对象的 QuerySet。这会将您当前的两个查询减少为一个,并保留您在 SQL 中指定的顺序。如果您能够进行升级,这是最好的选择。
根本不需要构建 Django 查询集或 Django 模型对象,只需将所需的所有字段添加到原始 SQL SELECT 中,然后直接从游标中使用这些行。如果您以后需要模型方法等,可能不是一个选择。
在 Python 代码中执行第三步,在其中迭代查询集并按照与从第一个查询返回的 ids 列表相同的顺序构造模型对象的 Python 列表。返回该列表而不是 QuerySet。如果您需要进一步过滤,将无法正常工作。
【讨论】:
谢谢,这就是我的想法。如果我可以再一次滥用你的善良:我之前做过#2,我只是觉得它很脏。无论如何构建一个查询集对象并按照我想要的顺序将项目粘贴到其中?我现在打算选择 2 或 3(网站今晚/明天启动),但我想知道这是否可能。 可能吗?当然。容易或简单或干净?不,没有理由这样做。如果您现在需要一个肮脏的 hack,请使用 #2 或 #3。稍后正确的选项是 #1 或 GeoDjango。以上是关于Django 按计算字段排序的主要内容,如果未能解决你的问题,请参考以下文章