Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在GeoDjango中将距点的距离添加为注释_Django_Django Models_Postgis_Geodjango - Fatal编程技术网

如何在GeoDjango中将距点的距离添加为注释

如何在GeoDjango中将距点的距离添加为注释,django,django-models,postgis,geodjango,Django,Django Models,Postgis,Geodjango,我有一个带有单点域的地理模型,我希望为每个模型到给定点的距离添加一个注释,我可以在以后进行过滤并进行额外的拼凑 有一个明显的queryset.distance(to_point)函数,但它实际上并没有注释queryset,它只是向queryset中的每个模型添加了一个distance属性,这意味着我以后无法对其应用.filter(distance_ulte=some_distance) 我也知道通过字段和距离本身进行过滤,如下所示: queryset.filter(point__distance

我有一个带有单点域的地理模型,我希望为每个模型到给定点的距离添加一个注释,我可以在以后进行过滤并进行额外的拼凑

有一个明显的
queryset.distance(to_point)
函数,但它实际上并没有注释queryset,它只是向queryset中的每个模型添加了一个distance属性,这意味着我以后无法对其应用
.filter(distance_ulte=some_distance)

我也知道通过字段和距离本身进行过滤,如下所示:

queryset.filter(point__distance_lte=(to_point, D(mi=radius)))
但是,由于我想做多个过滤器(以获得不同距离范围内的模型计数),我真的不想让DB每次都计算到给定点的距离,因为这可能会很昂贵


有什么想法吗?具体来说,是否有办法将其添加为常规注释而不是每个模型的插入属性?

我找不到任何烘焙方法,因此最后我创建了自己的聚合类:

这只适用于post_gis,但为另一个geo db创建一个也不太复杂

from django.db.models import Aggregate, FloatField
from django.db.models.sql.aggregates import Aggregate as SQLAggregate


class Dist(Aggregate):
    def add_to_query(self, query, alias, col, source, is_summary):
        source = FloatField()
        aggregate = SQLDist(
            col, source=source, is_summary=is_summary, **self.extra)
        query.aggregates[alias] = aggregate


class SQLDist(SQLAggregate):
    sql_function = 'ST_Distance_Sphere'
    sql_template = "%(function)s(ST_GeomFromText('%(point)s'), %(field)s)"
这可以按如下方式使用:

queryset.annotate(distance=Dist('longlat', point="POINT(1.022 -42.029)"))

如果有人知道更好的方法,请告诉我(或者告诉我为什么我的方法很愚蠢)

您可以使用GeoQuerySet.distance

cities = City.objects.distance(reference_pnt)
for city in cities:
    print city.distance()

编辑:添加距离属性和距离过滤器查询

usr_pnt = fromstr('POINT(-92.69 19.20)', srid=4326)
City.objects.filter(point__distance_lte=(usr_pnt, D(km=700))).distance(usr_pnt).order_by('distance')

  • 距离
  • 距离
  • 距离
  • 距离
  • 德威辛

现代方法之一是设置“输出字段”参数,以避免“不正确的几何输入类型:»。使用我们的输出场django试图将ST_Distance球浮点结果转换为GEOField,但无法

    queryset = self.objects.annotate(
        distance=Func(
            Func(
                F('addresses__location'),
                Func(
                    Value('POINT(1.022 -42.029)'),
                    function='ST_GeomFromText'
                ),
                function='ST_Distance_Sphere',
                output_field=models.FloatField()
            ),
            function='round'
        )
    )

一种注释和排序的方法w/out GeoDjango。该模型包含坐标记录的外键,该坐标记录包含lat和lng属性

def get_nearby_coords(lat, lng, max_distance=10):
        """
        Return objects sorted by distance to specified coordinates
        which distance is less than max_distance given in kilometers
        """
        # Great circle distance formula
        R = 6371
        qs = Precinct.objects.all().annotate(
            distance=Value(R)*Func(
                    Func(
                        F("coordinates__lat")*Value(math.sin(math.pi/180)),
                        function="sin",
                        output_field=models.FloatField()
                    ) * Value(
                        math.sin(lat*math.pi/180)
                    ) + Func(
                        F("coordinates__lat")* Value(math.pi/180),
                        function="cos",
                        output_field=models.FloatField()
                    ) * Value(
                        math.cos(lat*math.pi/180)
                    ) * Func(
                        Value(lng*math.pi/180) - F("coordinates__lng") * Value(math.pi/180),
                        function="cos",
                        output_field=models.FloatField()
                    ),
                    function="acos"
                )
        ).order_by("distance")
        if max_distance is not None:
            qs = qs.filter(distance__lt=max_distance)
        return qs

这样做对我很有用(我可以在注释上应用过滤器)。 为了可读性而分解

from models import Address
from django.contrib.gis.measure import D
from django.contrib.gis.db.models.functions import Distance


intMiles  = 200
destPoint = Point(5, 23)

queryset0 = Address.objects.all().order_by('-postcode')
        
queryset1 = queryset0.annotate(distance=Distance('myPointField' , destPoint ))
queryset2 = queryset1.filter(distance__lte=D(mi=intMiles))

希望它能帮助一些人:)

Tats CLIVER,但是在注释点格式时应该像下面的point=“point(1.022-42.029)”示例:从django 1.11开始,没有名为aggregates的模块抛出。2020年有现成的解决方案吗?嘿,谢谢你的回答,但我在原始问题中提到了这一点。不幸的是,它不允许在距离属性上使用.filter()。或者至少它以前似乎没有。如果我的想法不正确,请随意扩展您的答案,详细说明如何以这种方式使用,如果我可以复制,我会将您的答案更改为可接受的答案。@TomDickin我更新了几个示例,显示了距离查询和顺序。这将返回什么?有没有一种方法可以在没有DB的情况下执行类似的操作?如何将
srid=4326
传递到