按相对于给定位置的距离排序查询集

Ordering queryset by distance relative to a given position

我有一个包含纬度和经度信息的模型作为 FloatFields。

class Trader(models.Model):
    latitude = models.FloatField()
    longitude = models.FloatField()

我想通过增加距给定位置(纬度、经度)的距离来对该模型进行排序,但似乎无法使用 F() 表达式(使用 haversine 库,我没有成功转换他们变成浮点数)

Trader.objects.all().annotate(distance=haversine((lat, lon), (float(F('latitude')), float(F('longitude'))))).order_by('distance')

此查询抛出以下类型错误:

float() argument must be a string or a number

我也尝试过将 ExpressionWrapper 与 FloatField() 作为 output_field 参数一起使用,但没有成功。

我怎样才能做到这一点?

提前感谢您的帮助!

请注意 https://docs.djangoproject.com/en/1.8/ref/models/expressions/#f-expressions "generates SQL" 和 float("generate sql") 没有意义。 "generate sql" == 使用生成的 sql 字段的值。您将不得不用知道如何将自身翻译成 sql 的东西来更改 haversine 函数,它会进行大量计算并且是 django 的朋友...

你肯定需要发挥创意才能优雅地解决这个问题。如果您可以编写 sql 来进行计算,原始 sql 似乎是获得结果的最快方法。考虑使用像 postgis 这样的地理扩展。如果您有一组较小且固定的输入(纬度、经度)组合或 "precompute estimations" 可以考虑预先计算,以便能够限制查询结果计数并在 python.[=11= 中计算和排序]

Func 是 Django 1.8 中的新内容。

from django.db.models import Func, F

class Sin(Func):
    function = 'SIN'

class Cos(Func):
    function = 'COS'

class Acos(Func):
    function = 'ACOS'

class Radians(Func):
    function = 'RADIANS'

radlat = Radians(latitude) # given latitude
radlong = Radians(longitude) # given longitude
radflat = Radians(F('latitude'))
radflong = Radians(F('longitude'))

Expression = 3959.0 * Acos(Cos(radlat) * Cos(radflat) *
                           Cos(radflong - radlong) +
                           Sin(radlat) * Sin(radflat))

Trader.objects.annotate(distance=Expression).order_by('distance')

基于this post.