具有动态半径的Django过滤器位置距离 [英] Django filter location distance with dynamic radius

查看:107
本文介绍了具有动态半径的Django过滤器位置距离的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在django的一个区域和一家商店中有2个模型,模型如下:

I have 2 model in django a zone and a shop, models are like this:

from django.contrib.gis.db import models
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
from location_field.models.spatial import LocationField


class Zone(models.Model):
    name = models.CharField(max_length=200)
    location_point = LocationField(based_fields=['city'], zoom=7, default=Point(51.67, 32.65))
    radius = models.IntegerField(default=1000)  # radius in meters

class Shop(models.Model):
    name = models.CharField(max_length=200)
    location_point = LocationField(based_fields=['city'], zoom=7, default=Point(51.67, 32.65), null=True, blank=True)
    zone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=True)

LocationField 是一个PointField机智在django管理员中找到更好的地图。

LocationField is a PointField with a better map in django admin.

我想在每个商店中根据商店位置,区域位置和半径自动选择区域。如果没有半径可支持车间的区域,则将为无。我尝试了以下查询:

I want on every shop saving select zone automatically base on shop location , zone location and radius. If there is no zone with radius to support shop it will be None. I tried this query:

zone_list = Zone.objects.filter(
    location_point__distance_lte=(
        shop.location_point, D(m=models.F('radius'))
    )
)

但是我得到这个错误:


TypeError:float()参数必须是字符串或数字,而不是'F'

TypeError: float() argument must be a string or a number, not 'F'

我该如何解决?

推荐答案

这似乎发生在 django.contrib.gis.measure MeasureBase 类内(其中 Distance / D 的继承人),更具体地说,是 default_units 方法中尝试投射 str 或数字输入值改为 float ,但改为接收 F 表达式。

That seems to happen inside the MeasureBase class of django.contrib.gis.measure (which Distance/D inherits from) and more specifically in the default_units method where it tries to cast str or numeric input values to float but receives an F expression instead.

我们可以采取的解决方法是 Distance 请注意此 Distance 方法,因为它来自 shop.location_point 与当前 > location_point ,然后我们可以按距离< = 而不是实例 radius :

What we can do as a workaround, is to annotate the Distance (careful with this Distance method because it comes from the GeoDjango Geographic Database Functions) between the shop.location_point and the current location_point and then we can filter by that distance being <= than the instance radius:

from django.contrib.gis.db.models.functions import Distance

zone_list = Zone.objects.annotate(
    distance=Distance('location_point', shop.location_point)
).filter(distance__lte=F('radius'))

对@ e4c5的出色回答表示敬意: GeoDjango根据与模型字段的距离进行过滤

Kudos to this excellent answer from @e4c5: GeoDjango filter by distance from a model field

另一种方法是完全消除注释部分,并直接通过 Distance 进行过滤:

Another approach would be to eliminate the annotation part entirely and go straight to the filtering by Distance:

from django.contrib.gis.db.models.functions import Distance

zone_list = Zone.objects.filter(
    radius_gte=Distance('location_point', shop.location_point)
)



我在此保留评论的连续性:

您可以尝试投射 F('使用FloatField()的结果) ref / models / database-functions /#cast rel = nofollow noreferrer> Cast() 方法将Integer转换为Float。

You can try to cast the F('radius') result as a FloatField() using the Cast() method to turn the Integer to a Float.

zone_list = Zone.objects.filter(
    location_point__distance_lte=(
        shop.location_point, 
        D(m=Cast('radius', output_field=models.FloatField()))
    )
)

这篇关于具有动态半径的Django过滤器位置距离的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆