GeoDjango 获取到给定位置集的任何点的给定距离内的模型的所有记录

Posted

技术标签:

【中文标题】GeoDjango 获取到给定位置集的任何点的给定距离内的模型的所有记录【英文标题】:GeoDjango Get all records of a model that are within a given distance to any of the points of a given set of locations 【发布时间】:2021-03-26 07:10:23 【问题描述】:

我正在尝试获取距离poi 500m 范围内的person(s) 列表。

我可以在 PostGIS 中实现这个目标:

    SELECT DISTINCT public.dbconn_person.id, 
        public.dbconn_person.name, 
        public.dbconn_person.location, 
        public.dbconn_poi.id, 
        public.dbconn_poi.name, 
        public.dbconn_poi.location
    FROM public.dbconn_person
    INNER JOIN public.dbconn_poi on st_dwithin(public.dbconn_person.location::geography,     public.dbconn_poi.location::geography, 500);

关键是我试图在 Django 中使用相同的查询,但我遇到了一些问题。

models.py

    class Person(models.Model):
        name = models.CharField(max_length = 120)
        location = models.PointField()

    class Poi(models.Model):
        name = models.CharField(max_length = 120)
        location = models.PointField()

view.py

    listpoi = Poi.objects.all()
    listperson = Person.objects.all()

我希望这样的事情会起作用,

    poi_filter = Person.objects.filter(location__dwithin=(Poi.objects.only('location'), 500))

据我所知,location_dwithin 函数似乎只接受单点。它是否正确?有什么方法可以使用 Django 实现我的 SQL 结果?

【问题讨论】:

【参考方案1】:

ST_DWITHIN 也不接受列表,但您的查询也不提供列表。因为是join条件,所以逐行进行1对1的比较。

Django 的 ORM 没有提供任意连接的方法,除了使用 .extra():

poi_table = Poi._meta.db_table
person_table = Person._meta.db_table
joined = Person.objects.extra(
    select="poi": f"poi_table.name",  # Add more fields as needed
    where=[
        f"ST_DWITHIN(person_table.location::geography,"
        f" poi_table.location::geography, 500)"
    ],
    tables=[poi_table],
)

这并不理想,但应该适合您的目的。

【讨论】:

我听说过.raw(),但没有听说过.extra()。我能够毫无问题地用 raw 重现我的查询,但似乎性能受到威胁。我找到了***.com/questions/7636859/…。我会尝试你的方法并比较结果和时间。谢谢 Extra 介于 raw orm 之间。在这两种情况下,您都将松散函数抽象并将自己与数据库实现联系在一起。我查看了FilteredRelation,但无法让它工作,感觉就像用叉子喝咖啡。性能问题不应该适用于任何一种情况,只要您获取您计划呈现的所有列(并将它们别名为重复名称)。【参考方案2】:

您可以从 POI 创建一个 MultiPoint 对象,然后像您的情况一样应用距离等空间查找功能。

from django.contrib.gis.geos import MultiPoint

points = tuple(Poi.objects.values_list("location", flat=True))
multipoint = MultiPoint(*points)
    
poi_filter = Person.objects.filter(location__dwithin=(multipoint, 500))

【讨论】:

以上是关于GeoDjango 获取到给定位置集的任何点的给定距离内的模型的所有记录的主要内容,如果未能解决你的问题,请参考以下文章

如何将地理位置添加到 OSQA?

给定 CLPlacemark 是不是可以获得该位置的图像?

使用 OpenStreetMap 获取给定 GPS 坐标集的国家名称

Spotify api 1.0.0 获取给定曲目集的播放列表的图像

获取查询集的当前 order_by 排序

如何在 bigquery 中使用 rowid 按日期获取数据集的第一个值,并将给定日期的所有其他值设为 0