【发布时间】:2021-02-22 15:26:05
【问题描述】:
我是 django 新手,有一个关于 db 查询的问题。
我目前正在使用原始查询来获取给定 lat lng x 半径内的位置。我的查询是
query = """SELECT id, (3959*acos(cos(radians(%2f))
*cos(radians(lat))*cos(radians(lng)-radians(%2f))
+sin(radians(%2f))*sin(radians(lat))))
AS distance FROM businesses_business WHERE approved > 0 HAVING
distance < %2f ORDER BY %s LIMIT %d OFFSET %d;""" % (
float(lat),
float(lng),
float(lat),
details['radius'],
details['orderBy'],
details['limit'],
details['offset']
)
我正在使用以下方法对数据进行序列化:
queryset = Business.objects.raw(query)
serialized_data = serializers.serialize('json', queryset)
我取回与业务模型匹配的数据。但是,我也想收到查询中计算的距离。我怎么能这样做,以便也返回每行的距离?
编辑:商业模式是:
class Business(models.Model):
name = models.CharField(max_length=50, verbose_name="Name")
lat = models.FloatField(verbose_name="Latitude",
null=True,
blank=True)
lng = models.FloatField(verbose_name="Longitude",
null=True,
blank=True)
approved = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
业务模型中没有distance,它是在查询中动态计算的。这个想法是拥有多个企业,用户可以在他们自己的 lat/lng x 英里范围内搜索企业。我可以退回符合半径标准的商家,但我也想显示实际距离,这是我目前无法做到的。
附言如果有更好的方法来做到这一点,那么我很想听听 :)
回答
最后我想出了如何做到这一点,在我做这件事的同时,我还设法找到了一种更好的方法来完成上述工作。
首先,而不是使用Haversine公式;我使用GeoDjango Database API 根据距离过滤数据库中的项目。这意味着我不再需要使用原始查询。 然而 - 为此,我使用 PostGIS 扩展器从 MySQL 更改为 PostgreSQL,因为它具有更好的功能,可以在 SQL 中运行基于位置的查询。我能够做到这一点,因为我在我的项目中很早,所以它没有产生巨大的影响。
以下是 GeoDjango API 的示例:
queryset = Business.objects.filter(point__distance_lte=(pnt, D(mi=10)))
.annotate(distance=Distance("point", pnt))
然后我将distance 添加到序列化程序中,而不将distance 添加到模型中:
class BusinessSerializer(serializers.ModelSerializer):
distance = serializers.SerializerMethodField()
def get_distance(self, obj):
try:
return obj.distance.mi
except BaseException:
return None
class Meta:
fields = ('name', 'distance')
model = models.Business
现在,当我使用 BusinessSerializer 时,它也会返回 distance :)
快乐的日子。
【问题讨论】: