具有动态半径的 Django 过滤器位置距离
Django filter location distance with dynamic radius
我在 django 中有 2 个模型,一个区域和一个商店,模型是这样的:
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 admin 中有更好的地图。
我希望每个商店根据商店位置、区域位置和半径自动保存 select 区域。如果没有以支持商店为半径的区域,它将是 None。我试过这个查询:
zone_list = Zone.objects.filter(
location_point__distance_lte=(
shop.location_point, D(m=models.F('radius'))
)
)
但是我得到这个错误:
TypeError: float() argument must be a string or a number, not 'F'
我该如何解决这个问题?
这似乎发生在 django.contrib.gis.measure
的 MeasureBase
class 内部(Distance
/D
inherits from) and more specifically in the default_units
method 它试图将 str
或数字输入值转换为 float
但收到 F
表达式。
我们可以做的解决方法是 annotate
Distance
(小心这个 Distance
方法,因为它来自shop.location_point
和当前 location_point
之间的 GeoDjango 地理数据库函数 ) 然后我们可以过滤 <=
比实例 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 filter by distance from a model field
另一种方法是完全消除 annotation
部分并直接通过 Distance
:
进行过滤
from django.contrib.gis.db.models.functions import Distance
zone_list = Zone.objects.filter(
radius_gte=Distance('location_point', shop.location_point)
)
我把这个留在这里是为了评论的连续性:
您可以尝试将 F('radius')
结果转换为 FloatField()
,使用 Cast()
方法将整数转换为浮点数。
zone_list = Zone.objects.filter(
location_point__distance_lte=(
shop.location_point,
D(m=Cast('radius', output_field=models.FloatField()))
)
)
我在 django 中有 2 个模型,一个区域和一个商店,模型是这样的:
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 admin 中有更好的地图。
我希望每个商店根据商店位置、区域位置和半径自动保存 select 区域。如果没有以支持商店为半径的区域,它将是 None。我试过这个查询:
zone_list = Zone.objects.filter(
location_point__distance_lte=(
shop.location_point, D(m=models.F('radius'))
)
)
但是我得到这个错误:
TypeError: float() argument must be a string or a number, not 'F'
我该如何解决这个问题?
这似乎发生在 django.contrib.gis.measure
的 MeasureBase
class 内部(Distance
/D
inherits from) and more specifically in the default_units
method 它试图将 str
或数字输入值转换为 float
但收到 F
表达式。
我们可以做的解决方法是 annotate
Distance
(小心这个 Distance
方法,因为它来自shop.location_point
和当前 location_point
之间的 GeoDjango 地理数据库函数 ) 然后我们可以过滤 <=
比实例 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 filter by distance from a model field
另一种方法是完全消除 annotation
部分并直接通过 Distance
:
from django.contrib.gis.db.models.functions import Distance
zone_list = Zone.objects.filter(
radius_gte=Distance('location_point', shop.location_point)
)
我把这个留在这里是为了评论的连续性:
您可以尝试将 F('radius')
结果转换为 FloatField()
,使用 Cast()
方法将整数转换为浮点数。
zone_list = Zone.objects.filter(
location_point__distance_lte=(
shop.location_point,
D(m=Cast('radius', output_field=models.FloatField()))
)
)