在Django中返回附近位置
我有一个Django模型,它有一个自定义属性叫做 LocationField
。
class List(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=200)
location = LocationField(blank=True, max_length=255)
这个属性的值是以 纬度, 经度
的格式存储为字符串的。在我的模板中,我传递一个网址,格式是这样的: /nearby?lat='+某个值+'&long='+某个值
现在,我想根据传递的值返回 List
中的附近条目。
为此,我写了一个 views.py 的函数,代码如下:
def nearby(request):
if request.GET['lat']:
lat = request.GET['lat']
longitude = request.GET['long']
first_query = Playlist.objects.filter(location__istartswith=lat)
for f in first_query:
l = f.index(',')
n_string = f[l:]
为了让你明白我做了什么, first_query
返回所有以相同 纬度
开头的条目。不过,现在我还想匹配 经度
,所以我在运行一个 for 循环
,寻找分隔 纬度, 经度
的逗号在我的 LocationField
中的位置。 n_string
会提取 LocationField
的子字符串,然后我打算将其与我的 经度
变量进行匹配。
我的问题有两个部分:
- 我该如何生成匹配纬度的查询,并将其返回到模板中?
- 我该如何检查,比如说,在该区域周围2平方公里的范围内?
有没有Django的相关包可以用来解决这个问题?
3 个回答
你应该使用GIS数据库来存储坐标数据,并进行相关操作,比如搜索等。
如果要存储位置,可以使用这个链接中的内容:https://docs.djangoproject.com/en/dev/ref/contrib/gis/model-api/#pointfield
作为数据库,你可以选择这个链接中的PostGIS:https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/#postgis,或者这个Spatialite:https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/spatialite/
如果想要搜索附近的地点,可以使用距离查找,具体例子可以参考这个链接:https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-lookups
有至少三种方法可以做到这一点:
a) 哈弗辛距离(在MySQL中的例子)
def nearby_spots_old(request, lat, lng, radius=5000, limit=50):
"""
WITHOUT use of any external library, using raw MySQL and Haversine Formula
http://en.wikipedia.org/wiki/Haversine_formula
"""
radius = float(radius) / 1000.0
query = """SELECT id, (6367*acos(cos(radians(%2f))
*cos(radians(latitude))*cos(radians(longitude)-radians(%2f))
+sin(radians(%2f))*sin(radians(latitude))))
AS distance FROM demo_spot HAVING
distance < %2f ORDER BY distance LIMIT 0, %d""" % (
float(lat),
float(lng),
float(lat),
radius,
limit
)
queryset = Spot.objects.raw(query)
serializer = SpotWithDistanceSerializer(queryset, many=True)
return JSONResponse(serializer.data)
b) 使用Geodjango(PostgreSQL + PostGIS)
def nearby_spots_new(request, lat, lng, radius=5000, limit=50):
"""
WITH USE OF GEODJANGO and POSTGIS
https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-queries
"""
user_location = fromstr("POINT(%s %s)" % (lng, lat))
desired_radius = {'m': radius}
nearby_spots = Spot.objects.filter(
mpoint__distance_lte=(user_location, D(**desired_radius))).distance(
user_location).order_by('distance')[:limit]
serializer = SpotWithDistanceSerializer(nearby_spots, many=True)
return JSONResponse(serializer.data)
c) 一些聪明的查询(可以想象一个圆圈被一个正方形包围)
可以查看我的回答:如何过滤一个Django模型,使其经纬度坐标落在一定半径内