我有以下型号:Django的按距离排序
class Vacancy(models.Model):
lat = models.FloatField('Latitude', blank = True)
lng = models.FloatField('Longitude', blank = True)
我应该如何进行查询按距离排序(距离为无穷大)?
使用PosgreSQL,GeoDjango(如果需要)。
谢谢。
我有以下型号:Django的按距离排序
class Vacancy(models.Model):
lat = models.FloatField('Latitude', blank = True)
lng = models.FloatField('Longitude', blank = True)
我应该如何进行查询按距离排序(距离为无穷大)?
使用PosgreSQL,GeoDjango(如果需要)。
谢谢。
首先,这是更好地做,而不是把经纬度和LNT分离点场:
from django.contrib.gis.db import models
location = models.PointField(null=False, blank=False, srid=4326, verbose_name="Location")
然后,您可以像其过滤:
from django.contrib.gis.geos import *
from django.contrib.gis.measure import D
distance = 2000
ref_location = Point(1.232433, 1.2323232)
res = yourmodel.objects.filter(location__distance_lte=(ref_location, D(m=distance))).distance(ref_location).order_by('distance')
已经有像stackoverlow中的几个问题,如果你检查它们会更好。
这是我想明白,为什么在这个查询过滤器,当我不能只是︰'res = mymodel.objects.order_by('location')' – Rukomoynikov
如果你想对位置进行排序,应该有一个参考位置。您可以对特定位置的记录进行排序。 – cem
而在您的查询中:D(m =距离),距离是否可变? – Rukomoynikov
这是一个不需要GeoDjango使用自定义管理器的解决方案。
class LocationManager(models.Manager):
def nearby(self, latitude, longitude, proximity):
"""
Return all object which distance to specified coordinates
is less than proximity given in kilometers
"""
# Great circle distance formula
gcd = """
6371 * acos(
cos(radians(%s)) * cos(radians(latitude))
* cos(radians(longitude) - radians(%s)) +
sin(radians(%s)) * sin(radians(latitude))
)
"""
return self.get_queryset()\
.exclude(latitude=None)\
.exclude(longitude=None)\
.annotate(distance=RawSQL(gcd, (latitude,
longitude,
latitude)))\
.filter(distance__lt=proximity)\
.order_by('distance')
class Location(models.Model):
objects = LocationManager()
latitude = models.FloatField()
longitude = models.FloatField()
...
用途如下:
eiffel_tower_5k = Location.objects.nearby(48.8582, 2.2945, 5)
如果你使用SQLite,你需要的地方添加
from django.db.backends.signals import connection_created
from django.dispatch import receiver
@receiver(connection_created)
def extend_sqlite(connection=None, **kwargs):
if connection.vendor == "sqlite":
# sqlite doesn't natively support math functions, so add them
cf = connection.connection.create_function
cf('acos', 1, math.acos)
cf('cos', 1, math.cos)
cf('radians', 1, math.radians)
cf('sin', 1, math.sin)
的.distance(ref_location)
在Django被删除> = 1.9,你应该用注解来替代。
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.measure import D
ref_location = Point(1.232433, 1.2323232, srid=4326)
yourmodel.objects.filter(location__distance_lte=(ref_location, D(m=2000))).annotate(distance=Distance('location', ref_location)).order_by('distance')
也应该缩小与使用空间索引的dwithin
运营商的搜索,距离不使用减慢查询了指数:
yourmodel.objects.filter(location__dwithin=(geom, 0.02))
.filter(location__distance_lte=(ref_location, D(m=2000)))
.annotate(distance=Distance('location', ref_location))
.order_by('distance')
看到this post为location__dwithin=(geom, 0.02)
解释
注意:'D'实际上是'django.contrib.gis.measure.Distance',它痛苦地与模型函数共享相同的名字 –
如果你不想/没有机会使用gis,这里是溶剂(django orm sql中的半径距离函数写入器):
lat = 52.100
lng = 21.021
earth_radius=Value(6371.0, output_field=FloatField())
f1=Func(F('latitude'), function='RADIANS')
latitude2=Value(lat, output_field=FloatField())
f2=Func(latitude2, function='RADIANS')
l1=Func(F('longitude'), function='RADIANS')
longitude2=Value(lng, output_field=FloatField())
l2=Func(longitude2, function='RADIANS')
d_lat=Func(F('latitude'), function='RADIANS') - f2
d_lng=Func(F('longitude'), function='RADIANS') - l2
sin_lat = Func(d_lat/2, function='SIN')
cos_lat1 = Func(f1, function='COS')
cos_lat2 = Func(f2, function='COS')
sin_lng = Func(d_lng/2, function='SIN')
a = Func(sin_lat, 2, function='POW') + cos_lat1 * cos_lat2 * Func(sin_lng, 2, function='POW')
c = 2 * Func(Func(a, function='SQRT'), Func(1 - a, function='SQRT'), function='ATAN2')
d = earth_radius * c
Shop.objects.annotate(d=d).filter(d__lte=10.0)
PS 改款车型,变化滤波器ORDER_BY,更改关键字和参数化
PS2 为sqlite3的,你应当确保有可用功能SIN,COS,弧度,ATAN2,SQRT
[阅读](https://docs.djangoproject.com/en/1.5/ref/models/options/#django.db.models.Options.order_with_respect_to)[docs](https://docs.djangoproject.com/en /1.5/ref/contrib/gis/)! – FallenAngel
是的,我读过。但没有明白。将再次阅读。)谢谢。 – Rukomoynikov
什么距离。什么距离? –