GeoDjango根据与模型字段的距离进行过滤

lac*_*lac 5 python django geodjango

我的问题与几乎相同。但是它已经很老了,感觉必须是一个比较常见的情况,可能会有更好的解决方案。

我有一个类似的模型:

class Person(models.Model):
    location = models.PointField(srid=4326)
    willing_to_travel = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

如果我想要在某个点的固定距离(例如10英里)内的Person的所有实例p,我可以这样做:

Person.objects.filter(location__distance_lte=(p, D(mi=10)))
Run Code Online (Sandbox Code Playgroud)

但是我想获得在willing_to_travel特定位置距离内的Person的所有实例。

e4c*_*4c5 4

这要归功于Django 1.9 中引入的地理数据库函数

允许用户访问 Django 中注释、聚合或过滤器中使用的地理数据库函数。

我们最感兴趣的是Distance,它可以应用于您的案例,如下所示:

from django.contrib.gis.db.models.functions import Distance
from django.db.models import F
Person.objects.annotate(distance=Distance('location', p)
       ).filter(distance__lte=F('willing_to_travel'))
Run Code Online (Sandbox Code Playgroud)

请注意,这里有细微的差别,我们没有直接使用distance_lte,而是创建了一个注释来生成距离列。然后我们使用模型查询集的标准 __lt 比较。这(大致)翻译成

   ... WHERE ST_Distance(app_person.location, ST_GeogFromWKB(...)) < 
       app_person.willing_to_travel
Run Code Online (Sandbox Code Playgroud)

这与使用 ST_Dwithin 生成的类似,distance_lte它不如使用 ST_Dwithin 的高效,但它可以完成工作

您需要将位置转换为地理,因为此查询对“字段单位”进行操作,这意味着度数。如果您使用地理字段,距离将以米为单位。